Для синхронізації взаємодії процесів з|із| ресурсом, що розділяється, часто використовують семафори. Семафори виконують функцію відповідну своїй назві: замикають доступ до ресурсу одним процесом (з|із| тих, що взаємодіють) і вирішують доступ до іншого.
SERVER CLIENT
Читання Запис
Hello,World
Для роботи з|із| семафором необхідно забезпечити виконання наступних|слідуючих| умов:
1. Семафори повинні бути «видно» всім взаємодіючим процесам;
2. Фрагменти коду по перемиканню станів семафора повинні бути безперервними, тобто потрібно забезпечити атомарність критичних операцій.
З|із| цього виходить, що семафори повинні бути системними ресурсами. Єдино можливим способом гарантування атомарності виконання критичних ділянок операцій є|з'являється,являється| їх виконання в режимі ядра. Семафор є групою окремих «семафорчиків»,| об'єднаних|з'єднаних| загальними|спільними| ознаками (ідентифікатор, дескриптор). Кожний з семафорів може приймати будь-яке не негативне|заперечне| число, дозволене в даній ОС. Якщо семафор приймає значення тільки|лише| 0 або 1, його називають бінарним.
Розглянемо|розгледимо| завдання|задачу|, в якому:
- Взаємодіють два самостійні процеси, створені програмами Server і Client;
- Server виділяє пам'ять, що розділяється, створює семафор і читає з пам'яті;
- Client підключає пам'ять, що розділяється, вже готовий семафор, записує|занотовує| в пам'ять, що розділяється, рядок, відключає і звільняє|визволяє| пам'ять, звільняє|визволяє| семафор.
Для створення|створіння| семафора використовується функція:
int semget (key_ tKey, int nsems, int semflag); - створює семафор і повертає його ID.
Тут:
- Key - унікальний ключ|джерело|, який використовуватимуть всі процеси, що звертаються|обертаються| до цього семафора;
- nsems - кількість семафорів;
- semflag - прапори (аналогічні прапорам функції shmget()).
Після того, як семафор створений, з|із| ним можна працювати, для цього необхідно:
- Визначити у файлі заголовка операції для семафора;
- Виконати ці операції в програмі.
Для виконання операції над семафором використовується:
semop (int semid, struct sembuf *semop, size_t nops);
Тут:
- semid - ідентифікатор семафора над яким потрібно виконати дію;
- nops - річ у тому, що|справа в тому, що,дело в том | для виконання дії може бути потрібно декілька операцій, це указується|вказується| даним параметром;
- struct sembuf *semop - власне операція над семафором, задається структурою semop, покажчик на яку передається другим параметром.
Розглянемо|розгледимо| допустимі значення операції над семафорами:
Позитивне число - поточне значення семафора збільшується на це значення
Рівне «0» - процес чекає поки семафор не обнулиться
Негативне|заперечне| число - процес чекає поки значення семафора не стане рівним модулю цього числа, а потім віднімає модуль цієї величини, тобто|цебто| результат «0»
Із сказаного виходить:
- Перше значення тільки|лише| змінює|зраджує| значення семафора;
- Друге тільки|лише| перевіряє чи не обнулився семафор;
- Третє перевіряє, а потім змінює|зраджує| значення семафора.
Розглянемо|розгледимо| два приклади|зразки| в яких:
1. задається операція над семафором;
2. записується|занотовується| функція, що виконує цю операцію.
Перший приклад|зразок|:
Умовимося вважати|лічити|, що семафор бінарний (його значення можуть приймати або "0" або "1"), а також, що значення "0" - вирішує доступ до ресурсу, а "1" - блокує ресурс.
Визначимо операції:
Static struct sembuf sop_ lock[]={0,0,0},{0,1,0}
Запишемо функцію, виконуючу цю операцію:
Semop (semid,&sop_lock[0],2).
Запишемо операцію:
Static struct sembuf sop_ unlock[]={0-1,0};
Визначимо функцію:
Semop (semid,&sop_unlock[0],1);
Другий приклад|зразок|:
У ньому рахуємо значення семафора рівне "0" - замикає ресурс; "1" - вирішує (розблоковує ресурс).
Складемо операцію для замикання ресурсу:
Static struct sembuf sop_ lock[1]={0-1,0}
Semop (semid,&sop_lock[0],1);
Static struct sembuf sop_unlock[1]={0,1,0};
Semop (semid,&sop_unlock[0],1);
Server.c
int main()
{
printf("Server start\n");
Message *msgptr;
key_t key;
int shmid, semid;
key=ftok("server",1);
shmid=shmget(key,sizeof(Message),PERM | IPC_CREAT);
msgptr = (Message*)shmat(shmid,0,0);
semid = semget(key,2,PERM | IPC_CREAT);
semop(semid,&proc_wait[0],1);
semop(semid,&mem_lock[0],2);
printf("Client send message: %s",msgptr->buff);
semop(semid,&mem_unlock[0],1);
shmdt(msgptr);
printf("Server exit\n");
exit(0);
}
Client.c
int main()
{
printf("Client start\n");
Message *msgptr;
key_t key;
int shmid,semid;
key=ftok("server",1);
shmid=shmget(key,sizeof(Message),0);
msgptr=(Message*)shmat(shmid,0,0);
semid=semget(key,2,PERM);
semop(semid,&mem_lock[0],2);
semop(semid,&proc_start[0],1);
sprintf(msgptr->buff,"Hello world!\n");
printf("Client send message 'Hello world'\n");
semop(semid,&mem_unlock[0],1);
semop(semid,&mem_lock[0],2);
shmdt(msgptr);
shmctl(shmid,IPC_RMID,0);
semctl(semid,0,IPC_RMID);
printf("Client exit\n");
exit(0);
}
Shmem.h
#define MAXBUFF 80
#define PERM 0666
typedef struct mem_msg
{
int segment;
char buff[MAXBUFF];
}Message;
struct sembuf proc_wait[1]={1,-1,0};
struct sembuf proc_start[1]={1,1,0};
struct sembuf mem_lock[2]={0,0,0,0,1,0};
struct sembuf mem_unlock[1]={0,-1,0};