Средства межпроцессного взаимодействия (IPC) в ОС LINUX. Семафоры и разделяемая память. Ненадежные сигналы, страница 6

6. Семафоры и разделяемая память.

Работа с разделяемой памятью продемонстрирована на примере клиент-серверного приложения. Множество клиентов отправляет сообщения серверу, который принимает их и выводит на экран.

Для синхронизации доступа процессов к разделяемой памяти использоваться семафоры, которые так же будут хранится в разделяемой памяти.

Обобщенная структура клиент-серверного приложения.          


Рис. 6.1. Структура приложения.

Идея примера взята из [1] (Глава 13, разделяемая память POSIX).

Листинг 6.1. Структура буфера сообщений  разделяемой памяти. Файл shared_mem.h.

/*

* shared_mem.h

* Определение содержимого буфера в разделяемой памяти

*/

#ifndef SHARED_MEM_H_

#define SHARED_MEM_H_

#define      SHM_NAME            "server_shm"

#define      PERM                0666

#define      MAX_MSG_SIZE        256

#define      MAX_NUM_MSG         16

/* Структура буфера в разделяемой памяти */

struct SharedMem

{

sem_t mutex;

sem_t nempty;

sem_t nstored;

int    nput;

long   msg_offset[ MAX_NUM_MSG ];

char   msg_data[ MAX_NUM_MSG*MAX_MSG_SIZE ];

};

#endif

Буфер в разделяемой памяти представляет собой кольцевой буфер. Для синхронизации доступа к общему буферу используются три семафора.

·  Бинарный семафор mutex защищает критические области кода, такие как чтение и запись в буфер. Используется для взаимоисключения доступа к буферу и инициализируется единицей.

·  Семафор-счетчик nempty подсчитывает число свободных полей и инициализируется значением MAX_NUM_MSG.

·  Семафор-счетчик nstored подсчитывает число заполненных полей в буфере  и инициализируется значением 0.

Листинг 6.2. Программа-сервер.

/*

* IPC POSIX

* Семафоры и разделяемая память

* Программа сервера

*/

#include <stdlib.h>

#include <stdio.h>

#include <semaphore.h>

#include <sys/mman.h>

#include <fcntl.h>

#include <signal.h>

#include "shared_mem.h"

void sigint_handler( int );

int main( int argc, char *argv[] )

{

struct SharedMem *p_shmem;

int    fd_shm;

/* Создание и отображение объекта разделяемой памяти */

shm_unlink( SHM_NAME );

fd_shm = shm_open( SHM_NAME, O_RDWR | O_CREAT | O_EXCL, PERM );

if( fd_shm < 0 )

{

printf( "Server: open/create shared memory error!!!\n");

exit(2);

}

p_shmem = mmap( NULL, sizeof(struct SharedMem), PROT_READ | PROT_WRITE, MAP_SHARED, fd_shm, 0);

/* Установка размера объекта разделяемой памяти */

ftruncate( fd_shm, sizeof(struct SharedMem) );

close( fd_shm );

printf( "Server: start.\n");

signal( SIGINT, sigint_handler );

/* Инициализация массива сдвигов */

int i;

for( i=0; i<MAX_NUM_MSG; ++i )

{

p_shmem->msg_offset[i] = i * MAX_MSG_SIZE;

}

/* Инициализация семафоров */

sem_init( &(p_shmem->mutex), 1, 1 );

sem_init( &(p_shmem->nempty), 1, MAX_NUM_MSG  );

sem_init( &(p_shmem->nstored), 1, 0 );

/* Серверная часть программы */

i = 0;

long   offset;

for ( ; ; )

{

sem_wait( &(p_shmem->nstored) );

sem_wait( &(p_shmem->mutex) );

offset = p_shmem->msg_offset[i];

printf( "Message: %s\n", &p_shmem->msg_data[ offset ] );

/* Циклический буфер */

if ( ++i >= MAX_NUM_MSG )

{

i = 0;

}

sem_post( &(p_shmem->mutex) );

sem_post( &(p_shmem->nempty) );

}

return EXIT_SUCCESS;

}

void sigint_handler( int signo )

{

printf( "Server: terminate. Shared memory deleted.\n");

shm_unlink( SHM_NAME );

exit(0);

}

Программа-сервер ожидает записи в память хотя бы одного сообщения, потом читает сообщение, и увеличивает число свободных полей в буфере.

Завершение программы осуществляется по сигналу SIGINT, в обработчике происходит удаление объекта разделяемой памяти.

Листинг 6.3. Программа-клиента.

/*

* IPC POSIX

* Семафоры и разделяемая память

* Программа клиента

*/

#include <stdlib.h>

#include <stdio.h>