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>
Уважаемый посетитель!
Чтобы распечатать файл, скачайте его (в формате Word).
Ссылка на скачивание - внизу страницы.