ID:嵌入式情报局
作者:情报小哥
1什么是信号量?
01
形象理解
信号量说得简单一点就是一个非负计数整形变量,一旦占用了就会减1,释放就会加一,如果进程/线程需要占用信号量,而此时信号计数为0,则会把当前进程堵塞。
如果再形象一点那就类比生活中的交通灯,把程序的运行比作来往的车辆,而十字路口比作共享资源,信号量就类似于交通灯,起到协调各个进程有序的访问共享资源,这样就形成了进程的同步。
02
信号量分类
信号量也是一种进程中通信的方式,而该进程通信方式与前面介绍的稍有不同,其目的不是为了传递数据,而是用来保护共享资源(信号量也属于临界资源),使共享资源在任何时刻只能有规定的进程访问。
信号量主要分为两类:
- 二值信号量:信号量的值只有0和1,这和互斥量很类似,若资源被锁住,信号量的值为0,若资源可用,则信号量的值为1。但是信号量作为一种进程中的通信方式,与互斥量不同在于,互斥量只能由上锁的进程进行解锁,而信号量可以由其他进程进行解锁。
- 计数信号量:信号量的值在0到一个大于1的限制值之间,该计数表示可用的资源的个数。
03
使用参考模型
我们把P表示信号量的减1操作,而V表示信号量的加1操作,当然这里的加减1非我们平时的++或者--,PV都属于原子操作,下面简单的画一下信号量形成互斥的基本模型,如下图所示 :
当信号量单做互斥使用均初始化为1,当一个进程进行P操作便会减1,从而把临界资源锁定,在进程1还没有进行V操作释放信号量之前,若进程2进行P操作就会进行堵塞,从而等待进程1释放信号量,一旦进程1执行V操作,那么进程2便又有机会执行P操作(当然如果进程1一直不进行V操作,那么就会形成死锁),进程2利用临界资源,从而保障了临界资源的独占。
如果使用信号量来进行同步,就需要了解资源的特性和各个进程的制约关系,从而来确定信号量的初值以及PV操作。
2一些API介绍
这里小哥就介绍一下信号量的相关API,为后面的线程知识打基础。
1、创建(获取)信号量
semget()系统调用返回与参数键关联的SystemV信号量集标识符。
创建情形1 : 如果key的值为IPC_PRIVATE,
创建情形2 : 没有与key相关联的现有信号量集,并且在semflg中指定了IPC_CREAT,则创建一组新的nsems信号量。
如果semflg同时指定IPC_CREAT和IPC_EXCL,并且键已经存在一个信号量集,那么semget()失败,errno设置为EEXIST
key : IPC 键值,通常由 ftok() 生成,该值与创建消息队列、共享内存中使用的类似。
nsems:指定集合中包含的信号量个数;
semflg:该参数是多个标识的组合,其低 9 位指定用户对该信号量集合的权限。创建消息队列时常用0666 | IPC_CREAT。
2、信号量操作
该函数用于指定信号量集合中的某个信号量的动作 : 获取或者释放。成功返回 0,失败返回 -1。
semid:由 semget() 返回的信号量集合 ID;
sops:该参数指定了对 semid 信号量集合中某些信号量的操作,该值为 struct sembuf 结构体数组的首地址。其结构体内容如下:
1struct sembuf
2{
3 unsigned short sem_num; /* semaphore number */
4 short sem_op; /* semaphore operation */
5 short sem_flg; /* operation flags */
6}
sem_num:信号量集合中的信号量序号且从 0 开始,信号量的总数由 semget() 中的 nsems 指定。
sem_op :指定对序号为 sem_num 的信号量的操作。
- sem_op > 0,表示释放信号量,值的大小表示释放的信号量的个数。
- sem_op = 0,进程阻塞直到信号量的相应值为0,当信号量已经为0,函数立即返回。
- sem_op ,其绝对值表示程序想要占用的信号量的数量,如果信号量满足,将该信号量的值减去sem_op的绝对值,函数成功返回。如果此时 sem_num 指定的信号量没有足够的数量,那么程序将阻塞。
- IPC_NOWAIT : 指定对 sem_num 信号量的操作非阻塞。
- SEM_UNDO : 表示撤销操作。即不论程序是正常还是异常结束,sem_num 指定的信号量的值都会恢复为调用 semop() 之前的值,主要用于防止程序异常结束时未将占用的资源释放,导致资源永远被锁定的情况出现。
3最后
这里小哥就介绍了一下信号量和相关的API操作, 希望本文能够对你有帮助,今天就分享到这里,下期精彩见!
推荐好文 点击蓝色字体即可跳转
☞ 专辑|Linux应用程序编程大全
☞ 专辑|手撕C语言
我是情报小哥,一名嵌入式玩家!
长按前往图中包含的公众号关注