首先说明下System V
semaphore和Posix semaphore的区别
二者是信号量的两组程序设计接口函数。POSIX semaphore来源于POSIX技术规范的实时扩展方案(POSIX Realtime Extension),常用于线程;System V semaphore,常用于进程的同步。这两者非常相近,但它们使用的函数调用各不相同。前一种的头文件为semaphore.h,函数调用为sem_open()(Open Named Semaphore), sem_init() (Initialize Unnamed Semaphore),sem_wait(),sem_post(),sem_destory()等等。后一种头文件为<sys/sem.h>,函数调用为semctl(),semget(),semop()等函数。
本例中的信号量使用机制来源于mm共享库,一旦锁住便不可再进入,这里使用了struct
sembuf结构的二维数组,是为了同时操作信号集,如dolock()后再dolock()就会被阻塞(只能等待dounlock()解救),因为my_dolock[1].sem_op
= 1使信号值为1,而在my_dolock[0].sem_op = 0中,只要当sem_op不为0就阻塞
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/sem.h>
union semun {
int val;
// used for SETVAL only
struct semid_ds *buf;
// used
for IPC_STAT and IPC_SET
ushort *array;
// used for GETALL and
SETALL
};
#if 01
int semid;
static union semun
my_semctlarg;
static struct sembuf my_dolock[2];
static struct sembuf my_dounlock[1];
int newSem();
void initSemBuf()
{
my_dolock[0].sem_num = 0;
my_dolock[0].sem_op = 0;
my_dolock[0].sem_flg = 0;
my_dolock[1].sem_num = 0;
my_dolock[1].sem_op = 1;
my_dolock[1].sem_flg = SEM_UNDO;
my_dounlock[0].sem_num = 0;
my_dounlock[0].sem_op = -1;
my_dounlock[0].sem_flg = SEM_UNDO;
semid = newSem();
}
int dolock()
{
int ret = -1;
* __sops, which is a pointer to the struct sembuf that you
filled with your semaphore commands. If you want, though, you can
make an array of struct sembufs in order to do a whole bunch of
semaphore operations at the same time. The way semop() knows that
you're doing this is the nsop argument, which tells how many struct
sembufs you're sending it. If you only have one, well, put 1 as
this argument.
while (((ret = semop(semid, my_dolock, 2))
< 0) && (errno ==
EINTR))
;
if (ret < 0)
{
perror("do lock semop :
");
abort();
}
return 0;
}
int dounlock()
{
int ret = -1;
while (((ret = semop(semid, my_dounlock, 1))
< 0) && (errno ==
EINTR))
;
if (ret < 0)
{
perror("do unlock semop :
");
abort();
}
return 0;
}
void showSem()
{
fprintf(stdout, "sem val: %d\n", semctl(semid,
0, GETVAL));
}
int newSem()
{
int semid = semget(321034, 10, IPC_CREAT |
IPC_EXCL | 0666);
if (semid < 0)
{
perror("semget : ");
abort();
}
my_semctlarg.val = 0;
semctl(semid, 0, SETVAL, my_semctlarg);
return semid;
}
void freeSem()
{
semctl(semid, 0, IPC_RMID);
}
int main()
{
initSemBuf();
int limit = 5;
pid_t pid;
if((pid = fork()) < 0){
freeSem();
return -1;
}
if(0 == pid){
srand(time(NULL)^getpid());
int i = 0;
while(i++ <
limit){
dolock();
int sec =
rand() & 255;
fprintf(stdout, "child doing work...\nafter %dms finish...\n\n",
sec);
usleep(sec);
dounlock();
}
}else{
srand(time(NULL)^getpid());
int i = 0;
while(i++ <
limit){
dolock();
int sec =
rand() & 255;
fprintf(stdout, "parent doing work...\nafter %dms finish...\n\n",
sec);
usleep(sec);
dounlock();
}
}
usleep(1000);
freeSem();
return 0;
}
#endif