============================================================
IPC --- System V IPC --- semaphores
Related System Calls:
[designed to work for arrays of semaphore values]
#include <sys/sem.h>
semctl
semget
semop
Basics:
Purpose: provide the feature for a single process to have exclusive access to a resource
Application scenes: multi-threaded programs, multiprocess programs or a combine of the two
General definition: two operations -- P(wait) and V(signal)
=> binaray semaphore (0,1)
=> general semaphore (0,1,2,...)
和file相似,不一样的进程会有不一样的semaphore identifier,可是,它们都指向同一个semaphore。(就像fd和inode)
对于file,不一样的进程用filename来获得file descriptors,对于semaphore,不一样的进程用key来获得不一样的semaphore identifiers。
用semaphore通讯的各个进程间,须要有个共同的key。
Analysis:
1. Linux Kernel是如何支持semaphore通讯机制的呢?
struct_task结构中有相应的semaphore的域,若是systemV IPC支持被编译进来,就能够支持。
2. semaphore主要是用来解决资源访问冲突的问题的。对于资源访问的竞争问题,有以下模型:
process1 |
process2 | <==> RESOURCE
process3 |
要使访问资源不由于出现竞争状态而出现不想要的结果,有两种方法。
第一,在resource侧作控制,组织多个进程同时访问,或者对将访问block。好比file lock
第二,在访问的process间作控制,使得他们可以互相通讯,从而解决访问冲突。
在Linux中,第二种解决方案,就是semaphore。
Examples:
#ifndef _JAMES_C_SEMAPHORE_H
#define _JAMES_C_SEMAPHORE_H
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
union semun
{
int val; /* value for SETVAL */
struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* array for GETALL SETALL */
struct seminfo __buf; /* buffer for IPC_INFO (Linux-specific) */
};
int set_semvalue(int sem_id);
void del_semvalue(int sem_id);
int semaphore_p(int sem_id);
int semaphore_v(int sem_id);
#endif
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include "mysem.h"
int set_semvalue(int sem_id)
{
union semun sem_union;
sem_union.val = 1;
if (semctl(sem_id, 0, SETVAL, sem_union) == -1)
return -1;
return 0;
}
void del_semvalue(int sem_id)
{
union semun sem_union;
if (semctl(sem_id, 0, IPC_RMID, sem_union) == -1)
perror("Failed to delete semaphore");
}
int semaphore_p(int sem_id)
{
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = -1; /* *P() */
sem_b.sem_flg = SEM_UNDO;
if (semop(sem_id, &sem_b, 1) == -1)
{
fprintf(stderr, "semaphore_p failed\n");
return -1;
}
return 0;
}
int semaphore_v(int sem_id)
{
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = 1;
sem_b.sem_flg = SEM_UNDO;
if (semop(sem_id, &sem_b, 1) == -1)
{
fprintf(stderr, "semaphore_v failed\n");
return -1;
}
return 0;
}
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include "mysem.h"
int main(int argc, char *argv[])
{
int sem_id;
int i;
int pause_time;
char op_char;
srand( (unsigned int)getpid() );
op_char = 'a' + rand()%26; /* other process */
sem_id = semget( (key_t)1234, 1, 0666 | IPC_CREAT);
if (argc > 1)
{
if ( set_semvalue(sem_id) < 0)
{
fprintf(stderr, "Failed to initialize semaphore\n");
exit(-1);
}
op_char = 'X'; /* creation process */
sleep(2);
}
for (i=0; i<5; i++)
{
if (semaphore_p(sem_id) < 0)
exit(-1);
printf("%c", op_char); fflush(stdout);
pause_time = rand()%3;
sleep(pause_time);
printf("%c", op_char); fflush(stdout);
if (semaphore_v(sem_id) < 0)
exit(-1);
sleep(pause_time);
}
printf("\n%d - finished\n", getpid());
if (argc > 1)
{
sleep(10);
del_semvalue(sem_id);
}
return 0;
}