应用程信号量有Posix信号量和SYSTEM信号,本文讨论的是SYSTEM V信号量,SYSTEM V信号量是SYSTEM V进程间通信的组成部分。SYSTEM V进程间通信包括:信号量,消息队列,共享内存。
函数包括如下:
先看一个有问题的代码,以下代码中,目的是实现父进程和子进程的对临界区资源访问的互斥,使对临界区资源的操作具有原子性,但实际运行中,并未实现父进程和子进程的互斥。SEM_UNDO的意思是当持有信号量的进程退出后,将自动释放信号量防止死锁。程序中父进程或子进程执行P操作后持有信号量,但进程很快结束退出,导致信号量被释放了,所有另一个进程执行P操作的时候没有阻塞。
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
union semun
{
int val;
struct semid_ds *buf;
unsigned short *array;
};
int sem_init(int sem_id, int init_valve)
{
union semun sem_union;
sem_union.val = init_valve; //初始化信号量的值
if( semctl(sem_id, 0, SETVAL, sem_union) )
{
perror("Initinal semaphore");
return -1;
}
return 0;
}
int sem_v(int sem_id)
{
struct sembuf sem_b;
sem_b.sem_num = 0; //信号量编号
sem_b.sem_op = 1;
sem_b.sem_flg = SEM_UNDO;
printf("v start\n");
if( semop(sem_id, &sem_b, 1)==-1 )
{
perror("V operation");
return -1;
}
printf("v end\n");
return 0;
}
int sem_p(int sem_id)
{
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = -1;
sem_b.sem_flg = SEM_UNDO;
printf("p start\n");
if( semop(sem_id, &sem_b, 1)==-1 )
{
perror("P operation\n");
return -1;
}
printf("p end\n");
return 0;
}
int main()
{
pid_t pid;
int sem_id;
sem_id = semget(ftok(".", 'a'), 1, 0666|IPC_CREAT );
sem_init(sem_id, 1); //初始化信号量的值
printf("sem_id:%d\n", sem_id);
pid = fork();
if(pid == -1)
{
perror("fork\n");
}
else if( pid == 0) //子
{
printf("sem_id:%d\n", sem_id);
sem_p(sem_id);
printf("child progress, pid=%d\n", getpid());
//sem_v(sem_id);
}
else //父
{
sleep(1);
sem_p(sem_id); //为什么不阻塞?
printf("farther pid=%d\n", getpid());
//sem_v(sem_id);
}
return 0;
}
对main函数的修改如下,实现了父进程和子进程的互斥。信号量的初始值为1,当子进程进行P操作后睡眠,父进程执行P操作时加阻塞,直到子进程执行V操作释放了信号量。
int main()
{
pid_t pid;
int sem_id;
sem_id = semget(ftok(".", 'a'), 1, 0666|IPC_CREAT );
sem_init(sem_id, 1); //初始化信号量的值
printf("sem_id:%d\n", sem_id);
pid = fork();
if(pid == -1)
{
perror("fork\n");
}
else if( pid == 0) //子
{
int i;
for(i=0; i<10; i++) {
printf("sem_id:%d\n", sem_id);
sem_p(sem_id, getpid());
printf("child progress, pid=%d\n", getpid());
sleep(1);
sem_v(sem_id,getpid());
sleep(1);
}
}
else //父
{
//sleep(10);
int i;
for(i=0; i<10; i++) {
sem_p(sem_id, getpid()); //
printf("farther pid=%d\n", getpid());
sleep(1);
sem_v(sem_id, getpid());
sleep(1);
}
}
return 0;
}