进程间通信——信号量
来源:互联网 发布:张靓颖是冯轲的m知乎 编辑:程序博客网 时间:2024/06/03 13:47
在说信号量之前我们再来复习一下几个概念:
1、把两个或多个执行流所能访问的同一块内存资源叫做临界资源
2、把访问临界资源的代码叫做临界区
3、在任意时刻只有一个执行流可以访问临界区,这种现象叫做互斥
4、一件事,要么做了,要么没有做,这叫做原子性
现在我们来看下什么事信号量
信号量:信号量的本质是一种数据操作锁(计数器)、用来负责数据操作过程中的互斥、同步等功能。
那么为什么要使用信号量呢?
使用信号量为了防止多个进程在访问临界资源为引发的问题。我们需要在任一时刻只能有一个执行线程访问代码的临界区域。临界区域是指执行数据更新的代码需要独占式地执行。信号量就可以提供这样的一种访问机制,让一个临界区同一时间只有一个线程在访问它, 也就是说信号量是用来调协进程对共享资源的访问的。
创建信号量用的函数是:
int semget(key_t key, int num_sems, int sem_flags);
第一个参数key是整数值(唯一非零),不相关的进程可以通过它访问一个信号量,它代表程序可能要使用的某个资源,程序对所有信号量的访问都是间接的,程序先通过调用semget函数并提供一个键,再由系统生成一个相应的信号标识符(semget函数的返回值),只有semget函数才直接使用信号量键,所有其他的信号量函数使用由semget函数返回的信号量标识符。如果多个程序使用相同的key值,key将负责协调工作。
第二个参数num_sems指定需要的信号量数目,它的值几乎总是1。
第三个参数sem_flags是一组标志,当想要当信号量不存在时创建一个新的信号量,可以和值IPC_CREAT做按位或操作。设置了IPC_CREAT标志后,即使给出的键是一个已有信号量的键,也不会产生错误。而IPC_CREAT | IPC_EXCL则可以创建一个新的,唯一的信号量,如果信号量已存在,返回一个错误。
除了这个函数,还有一些其它的函数
//改变信号量的值int semop(int sem_id, struct sembuf *sem_opa, size_t num_sem_ops);
其中:
struct sembuf{ short sem_num;//除非使用一组信号量,否则它为0 short sem_op;//信号量在一次操作中需要改变的数据,通常是两个数, //一个是-1,即P(等待)操作,一个是+1,即V(发送信号)操作。 short sem_flg;//通常为SEM_UNDO,使操作系统跟踪信号, //并在进程没有释放该信号量而终止时,操作系统释放信号量 };
//控制信号量信息int semctl(int sem_id, int sem_num, int command, ...);
如果它有第四个参数,那么是:
union semun{ int val; struct semid_ds *buf; unsigned short *arry; };
SEM_UNDO
当操作信号量semop函数时,sem_flg可以设置SEM_UNDO标识;SEM_UNDO用于将修改的信号量值在进程正常退出(调用exit退出或main执行完)或异常退出(如段异常、除0异常、收到KILL信号等)时归还给信号量。
下面我们就来用代码实现信号量
//comm.c 1 #include"comm.h" 2 3 int CommSemSet(int flags,int nums) 4 { 5 key_t _key=ftok(PATHNAME,PROJ_ID); 6 if(_key<0) 7 { 8 perror("ftok"); 9 sleep(3); 10 return -1; 11 } 12 13 int semid=semget(_key,nums,flags); 14 if(semid<0) 15 { 16 perror("semget"); 17 sleep(3); 18 return -2; 19 } 20 return semid; 21 } 22 23 int CreateSemSet(int nums) 24 { 25 return CommSemSet(IPC_CREAT | IPC_EXCL | 0666, nums); 26 } 27 28 int GetSemSet() 29 { 30 return CommSemSet(0,0); 31 } 32 33 int InitSemSet(int semid, int nums) 34 { 35 union SemNo _sn; 36 _sn.val=1; 37 if(semctl(semid,nums,SETVAL,_sn)<0) 38 { 39 perror("semctl"); 40 sleep(3); 41 return -1; 42 } 43 return 0; 44 } 45 46 int CommPV(int semid,int nums,int flags) 47 { 48 struct sembuf _s[1]; 49 _s[0].sem_op=flags; 50 _s[0].sem_num=nums; 51 if(semop(semid,_s,1)<0) 52 { 53 perror("semop"); 54 sleep(3); 55 return -1; 56 } 57 return 0; 58 } 59 60 int P(int semid) 61 { 62 return CommPV(semid,0,-1); 63 } 64 int V(int semid) 65 { 66 return CommPV(semid,0,1); 67 } 68 int DestorySemSet(int semid) 69 { 70 if(semctl(semid,0,IPC_RMID)<0) 71 { 72 perror("semctl"); 73 sleep(3); 74 return -1; 75 } 76 return 0; 77 }
结果:
查看和删除信号量的命令:
ipcs -s //查看信号量ipcrm -s //删除信号量
最后在强调一点:信号量虽然是进程间通信的一种,但信号量不以通信为主要目的,它以保护临界资源为主要目的
- 进程间通信—信号量
- 进程间通信—信号量
- Linux进程间通信——信号量
- Linux进程间通信——信号量
- Linux进程间通信——信号量
- 进程间通信IPC——信号量
- Linux进程间通信——信号量
- Linux进程间通信——信号量
- 进程间通信——信号量
- 进程间通信——信号量
- 进程间通信——信号量
- Linux进程间通信——信号量
- 进程间通信——信号量
- 进程间通信——信号量
- 进程间通信——信号量
- Linux进程间通信——信号量
- 进程间通信之——信号量
- Linux进程间通信—使用信号量
- 后缀数组
- 学习C++的一些笔记(二)
- 初学者的Selenium自动化测试指南,基于Python(三)——浏览器相关操作
- 学习C++的一些笔记(三)
- git 安装笔记
- 进程间通信——信号量
- Activity的onStop和onPause的调用时机
- 笔记_递归调用的理解
- 数据结构–基本树
- C++ 数学小点
- 简单数据结构总结及常用排序算法
- LaTeX中的希腊字母输入
- shift+e 栅格捕捉
- 学习C++的一些笔记(四)