Linux进程间通信---信号量
Posted Ivan B.G. Liu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux进程间通信---信号量相关的知识,希望对你有一定的参考价值。
- 信号量是一个计数器,通常在内核中实现,用于多个进程对共享数据对象的同步访问。使用信号量的头文件是#include <sys/sem.h>
- 信号量的使用规则:
-
若信号量为正,则进程可使用该资源。
- 若信号量为0,则进程阻塞等待,并将进程插入等待队列,直到该信号量的值大于0从等待队列中执行进程请求。
- 加锁操作:如果信号量大于0,则信号量-1;如果信号量为0,则挂起该进程,并将这个进程插入等待队列。
- 解锁操作:如果等待队列中有进程则唤醒该进程,让它恢复运行;否则,信号量+1。
- Linux下使用信号量的常用函数:
- semget(key, num_sems, sem_flags):创建新的信号量或取得已有的信号量,key表示信号量的键值,不相关进程使用同一个key来访问同一个信号量,num_sems表示信号量个数(一般为1),sem_flags表示信号量访问权限,用IPC_CREAT与权限位与可保证信号量不存在时新建一个。函数返回一个int类型的数值,表示信号量的标识符。
- semop(sem_id, sem_opa, num_sem_ops):改变信号量的值,改变操作在sem_opa中,sem_opa是sumbuf结构体对象,使用方法如下:
struct sembuf { short sem_num; //除非使用一组信号量,否则它为0 short sem_op; //信号量在一次操作中需要改变的数据,通常是两个数,一个是-1,即P操作(加锁);一个是+1,即V操作(解锁) short sem_flg; //通常为SEM_UNDO,使操作系统跟踪信号,并在进程没有释放该信号量而终止时,操作系统释放信号量 };
- semctl(sem_id, sem_num, command, semun):控制信号量。commond中有:SETVAL初始化信号量为一个值,该值再semun结构体的val字段;IPC_RMID用于删除一个无需继续使用的信号量。
- 信号量的使用实例,同时开两个进程,每个进程中都用信号量同步临界区,在临界区中向屏幕打印字符:
#include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <sys/sem.h> union semun { int val; struct semid_ds *buf; unsigned short *arry; }; static int sem_id = 0; static int set_semvalue(); static void del_semvalue(); static int semaphore_p(); static int semaphore_v(); int main(int argc, char *argv[]) { char message = \'X\'; int i = 0; //创建信号量 sem_id = semget((key_t)1234, 1, 0666 | IPC_CREAT); if(argc > 1) { //程序第一次被调用,初始化信号量 if(!set_semvalue()) { fprintf(stderr, "Failed to initialize semaphore\\n"); exit(EXIT_FAILURE); } //设置要输出到屏幕中的信息,即其参数的第一个字符 message = argv[1][0]; sleep(2); } for(i = 0; i < 10; ++i) { //进入临界区 if(!semaphore_p()) exit(EXIT_FAILURE); //向屏幕中输出数据 printf("%c", message); //清理缓冲区,然后休眠随机时间 fflush(stdout); //离开临界区,休眠随机时间后继续循环 if(!semaphore_v()) exit(EXIT_FAILURE); sleep(2); } sleep(3); printf("\\n%d - finished\\n", getpid()); if(argc > 1) { //如果程序是第一次被调用,则在退出前删除信号量 sleep(3); del_semvalue(); } exit(EXIT_SUCCESS); } static int set_semvalue() { //用于初始化信号量,在sem_union的val字段中设置信号量初值。使用信号量之前必须先初始化! union semun sem_union; sem_union.val = 1; if(semctl(sem_id, 0, SETVAL, sem_union) == -1) return 0; return 1; } static void del_semvalue() { //删除信号量 union semun sem_union; if(semctl(sem_id, 0, IPC_RMID, sem_union) == -1) printf("Failed to delete semaphore\\n"); } static int semaphore_p() { //对信号量做减1操作,即加锁 P(sv) 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) { printf("semaphore_p failed\\n"); return 0; } return 1; } static int semaphore_v() { //这是一个释放操作,它使信号量变为可用,即解锁 V(sv) struct sembuf sem_b; sem_b.sem_num = 0; sem_b.sem_op = 1; //V() sem_b.sem_flg = SEM_UNDO; if(semop(sem_id, &sem_b, 1) == -1) { printf("semaphore_v failed\\n"); return 0; } return 1; }
ps:以上代码参考自https://blog.csdn.net/ljianhui/article/details/10243617,运行结果如下:
以上是关于Linux进程间通信---信号量的主要内容,如果未能解决你的问题,请参考以下文章