版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_35733751/article/details/82919091
1. 多个进程操作信号量
假设此时有多个进程在请求信号量发生阻塞时,且每个进程请求信号量减去的值都是一样的,那么到底哪个进程能继续执行是不确定的,这取决于调度算法。如果在阻塞的进程中,每个进程请求信号量减去的值都是不一样的,那么则会按照先满足条件的先执行的顺序进行。
例如此时有A和B两个进程阻塞,当前信号量的值为0,A进程请求将信号量值减去2,B进程请求将信号量减去1,当C进程请求将信号量加1时,此时信号量的值只有1,所以A进程并不满足要求,只有B进程满足条件,那么B进程会优先解除阻塞并执行,在某些情况下可能导致A进程一直无法满足条件并永远阻塞等待。
具体可参考semop函数的调用行为:39-System V——信号量第六小节。
2. 关于SEM_UNDO选项
如果一个进程在申请完信号量资源之后就终止了,不管是正常终止还是意外终止,默认情况下,信号量的值是不会发生改变的,这将会引发一个问题,如果当前还有进程阻塞,正等待释放信号量资源时,而之前的进程在退出时且没有正常释放信号量资源,那么当前的进程将会永远阻塞在这。
为了解决这个问题,可以在semop函数指定SEM_UNDO选项,然后内核会在进程终止后(无论是正常终止还是非正常终止),自动回收信号量资源。
sem1进程
#include <sys/types.h>
#include <sys/sem.h>
#include <sys/ipc.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
void print_sem(int semid)
{
//打印信号量
int ret;
unsigned short array[1] = {0};
ret = semctl(semid , 0 , GETALL , array);
if(ret < 0){
perror("semtcl error:");
}
printf("sem1 = %d\n" , array[0]);
}
int main(void)
{
int ret;
int semid = 0;
key_t key = 0x00112233;
//创建信号集,1个信号
semid = semget(key , 1 , IPC_CREAT | IPC_EXCL | 0664);
if(semid < 0){
perror("semget error:");
}
//设置信号量的值为1
int val = 1;
//通过val设置信号量
ret = semctl(semid , 0 , SETVAL , val);
if(ret < 0){
perror("semtcl error:");
}
//表示请求信号量1个资源,信号量值将减去1
struct sembuf buf1 = {0 , -1 , 0};
semop(semid , &buf1 , 1);
puts("sem1 is get sem");
sleep(8);
//进程1退出,此时进程1并没有正常释放信号量资源
return 0;
}
sem2进程
#include <sys/types.h>
#include <sys/sem.h>
#include <sys/ipc.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
void print_sem(int semid)
{
//打印信号量
int ret;
unsigned short array[1] = {0};
ret = semctl(semid , 0 , GETALL , array);
if(ret < 0){
perror("semtcl error:");
}
printf("sem1 = %d\n" , array[0]);
}
int main(void)
{
int ret;
int semid = 0;
key_t key = 0x00112233;
//获取信号量
semid = semget(key , 0 , 0);
if(semid < 0){
perror("semget error:");
}
print_sem(semid);
//表示请求信号量1个资源,信号量值将减去1
struct sembuf buf1 = {0 , -1 , 0};
//如果不满足条件,sem2则会一直阻塞在此
puts("sem2 is wait for sem");
semop(semid , &buf1 , 1);
puts("sem2 is get sem");
//释放信号量,释放1个资源,信号量的值将加1
struct sembuf buf2 = {0 , 1 , 0};
semop(semid , &buf2 , 1);
return 0;
}
程序执行结果:
由于sem1在退出时没有释放信号量资源,导致sem2进程一直阻塞。
当sem1指定SEM_UNDO选项后,程序执行结果如下:
struct sembuf buf1 = {0 , -1 , SEM_UNDO};
semop(semid , &buf1 , 1);
sem1在指定SEM_UNDO选项后,sem1退出时并没有释放信号量资源,此时将会由内核自动释放信号量资源,并且sem2申请信号量资源成功,解除阻塞状态。