您的位置:首页 > 运维架构 > Linux

linux信号量的SEM_UNDO参数

2016-04-15 22:29 465 查看
信号量是不同进程间或一个给定进程内部不同线程间同步的机制。System V信号量是一个或多个信号量的集合,其中的每一个都是氮素的计数信号量。System V信号量由内核维护,主要函数有:semget,semop,semctl。我们重点来讨论semop函数,该函数的主要功能是对信号进行PV操作。P操作负责把当前进程由运行状态转换为阻塞状态,知道另外一个进程唤醒它。操作为:申请一个空闲资源(把信号量减1),若成功,则退出,若失败,则该进程被阻塞。V操作负责把被阻塞的进程唤醒,它有一个参数表,存放着等待被唤醒的进程信息,操作为:释放一个被占用的资源(把信号量加1),如果发现有被阻塞的进程,则选择一个唤醒。semop函数原型:int semop(int semid,struct sembuf *sops,unsigned nsops)semop操作中:sembuf结构的sem_flg成员可以为0,IPC_NOWAIT,SEM_UNDO,为SEM_UNDO时,它将使操作系统跟踪当前进程对这个信号量的修改情况,如果这个进程在没有释放该信号量的情况下终止,操作系统将自动释放该进程持有的信号量。下面我们用一段程序来看看SEM_UNDO的作用: #include "comm.c"文件: static int comm_creat_sem_set(int _sem_nums,int flag) { key_t _key=ftok(_PATH_,_PROJ_ID_); if(_key<0) { perror("ftok"); return -1; } int sem_id=semget(_key,_sem_nums,flag); if(sem_id<0) { return -1; } return sem_id; } int creat_sem_set(int _sem_nums) { umask(0); int flag=IPC_CREAT|IPC_EXCL|0666; return comm_creat_sem_set(_sem_nums,flag); } int get_sem_set(int _sem_nums) { int flag=IPC_CREAT; return comm_creat_sem_set(_sem_nums,flag); } int init_sem_set(int _sem_id,int _sem_num,int _init_val) { union semun _un; _un.val=_init_val; if(semctl(_sem_id,_sem_num,SETVAL,_un)<0) { perror("semctl"); return -1; } return 0; } int p_sem(int _sem_id,int _seq_num) { struct sembuf _sem_buf[1]; _sem_buf[0].sem_num=_seq_num; _sem_buf[0].sem_op=-1; // _sem_buf[0].sem_flg=SEM_UNDO; _sem_buf[0].sem_flg=0; if(semop(_sem_id,_sem_buf,1)<0) { perror("semop"); return -1; } return 0; } int v_sem(int _sem_id,int _seq_num) { struct sembuf _sem_buf[1]; _sem_buf[0].sem_num=_seq_num; _sem_buf[0].sem_op=1; _sem_buf[0].sem_flg=0; // _sem_buf[0].sem_flg=SEM_UNDO; if(semop(_sem_id,_sem_buf,1)<0) { perror("semop"); return -1; } return 0; }comm.h文件: #pragma once #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> #define _PATH_ "." #define _PROJ_ID_ 0x6666 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*/ }; int creat_sem_set(int _sem_nums); int get_sem_set(int _sem_nums); int init_sem_set(int _sem_id,int _sem_nums,int _init_val); int p_sem(int _sem_id,int _seq_num); int v_sem(int _sem_id,int _seq_num); int destroy_sem_set(int _sem_id);sem.c文件: int main() { int sem_id=creat_sem_set(1); init_sem_set(sem_id,0,1); pid_t id=fork(); if(id <0) { perror("fork"); exit(1); } else if(id==0) { int childid=getpid(); int fatherid=getppid(); printf("childid:%d,fatherid:%d\n",childid,fatherid); int sem_id=get_sem_set(0); while(1) { p_sem(sem_id,0); printf("child wrinting\n"); sleep(1); fflush(stdout); printf("child finish post\n"); sleep(10); fflush(stdout); v_sem(sem_id,0); } } else { while(1) { p_sem(sem_id,0); printf("father wrinting\n"); sleep(1); fflush(stdout); printf("father finish post\n"); sleep(1); fflush(stdout); v_sem(sem_id,0); } } destroy_sem_set(sem_id); return 0; }在没用SEM_UNDO参数前,运行结果:

从代码中我们看到,在子进程P操作之后,我们让子进程sleep了10秒,在这之前我们把子进程傻掉了,也就是子进程没有进行V操作,所以没有释放占用的信号量,我们会看到,把子进程杀掉之后,父进程阻塞了。而我们用了SEM_UNDO这个参数后,运行结果如下:

我们可以看到,在把子进程kill后,父进程照样可以运行,因为使用了SEM_UNDO后,操作系统自动释放该进程持有的信号量,从而可以使得另一个进程可以继续工作。否则,另外一个进程将永远阻塞。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  linux SEM 信号量