sem_num对应信号集中的信号灯,其值是一个从0到相应的信号量集的资源总数(ipc_perm.sem_nsems)之间的整数,0对应第一个信号灯 。
sem_flg可取IPC_NOWAIT以及SEM_UNDO两个标志 。如果设置了SEM_UNDO标志,那么在进程结束时,相应的操作将被取消,这是比较重要的一个标志位 。如果设置了该标志位,那么在进程没有释放共享资源就退出时,内核将代为释放 。如果为一个信号灯设置了该标志,内核都要分配一个sem_undo结构来记录它,为的是确保以后资源能够安全释放 。事实上,如果进程退出了,那么它所占用的资源就释放了,但信号灯值却没有改变,此时,信号灯值反映的已经不是资源占有的实际情况,在这种情况下,问题的解决就靠内核来完成 。这有点像僵尸进程,进程虽然退出了,资源也都释放了,但内核进程表中仍然有它的记录,此时就需要父进程调用waitpid来解决问题了 。
sem_op的值大于0,等于0以及小于0确定了对sem_num指定的信号灯进行的三种操作 。具体请参考linux相应手册页 。(是信号量在一次操作中需要改变的数值(可以是非1的数值) 。通常只会用到两个值:-1----P操作,申请资源,如果已经没有资源可申请,则阻塞 。为阻塞原语;1---V操作,释放资源,为唤醒原语 。)
也许从实际含义上更好理解这些操作:信号灯的当前值记录相应资源目前可用数目;sem_op>0对应相应进程要释放sem_op数目的共享资源;sem_op=0可以用于对共享资源是否已用完的测试;sem_op<0相当于进程要申请-sem_op个共享资源 。再联想操作的原子性,更不难理解该系统调用何时正常返回,何时睡眠等待 。调用返回:成功返回0,否则返回-1 。
若sem_op 是正数,其值就加到semval上,即释放信号量控制的资源若sem_op 是0,那么调用者希望等到semval变为0,如果semval是0就返回;若sem_op 是负数,那么调用者希望等待到semval变为大于或等于sem_op的绝对值 。如果当前semval大于或等于sem_op的绝对值,则立即返回 。
这里需要强调的是semop同时操作多个信号灯,在实际应用中,对应多种资源的申请或释放 。semop保证操作的原子性,这一点尤为重要 。尤其对于多种资源的申请来说,要么一次性获得所有资源,要么放弃申请,要么在不占有任何资源情况下继续等待,这样,一方面避免了资源的浪费;另一方面,避免了进程之间由于申请共享资源造成死锁 。
3) int semctl(int semid,int semnum,int cmd,union semun arg) 该系统调用实现对信号灯的各种控制操作,参数semid指定信号灯集,参数cmd指定具体的操作类型;参数semnum指定对哪个信号灯操作,只对几个特殊的cmd操作有意义;arg用于设置或返回信号灯信息 。该系统调用详细信息请参见其手册页,这里只给出参数cmd所能指定的操作 。

文章插图
IPC_RMID Immediately remove the semaphore set, awakening all processes blocked in semop()
calls on the set (with an error return and errno set to EIDRM). The effective user ID
of the calling process must match the creator or owner of the semaphore set, or the
caller must be privileged. The argument semnum is ignored.
调用返回:调用失败返回-1,成功返回与cmd相关:

文章插图
5. 信号灯的限制1、一次系统调用semop可同时操作的信号灯数目SEMOPM,semop中的参数nsops如果超过了这个数目,将返回E2BIG错误 。SEMOPM的大小特定与系统,redhat 8.0为32 。
2、信号灯的最大值:SEMVMX,当设置信号灯值超过这个限制时,会返回ERANGE错误 。在redhat 8.0中该值为32767 。
3、系统范围内信号灯集的最大数目SEMMNI以及系统范围内信号灯的最大数目SEMMNS 。超过这两个限制将返回ENOSPC错误 。redhat 8.0中该值为32000 。
4、每个信号灯集中的最大信号灯数目SEMMSL,redhat 8.0中为250 。SEMOPM以及SEMVMX是使用semop调用时应该注意的;SEMMNI以及SEMMNS是调用semget时应该注意的 。SEMVMX同时也是semctl调用应该注意的 。
6. 竞争问题第一个创建信号灯的进程同时也初始化信号灯,这样,系统调用semget包含了两个步骤:创建信号灯;初始化信号灯 。由此可能导致一种竞争状态:第一个创建信号灯的进程在初始化信号灯时,第二个进程又调用semget,并且发现信号灯已经存在,此时,第二个进程必须具有判断是否有进程正在对信号灯进行初始化的能力 。在参考文献[1]中,给出了绕过这种竞争状态的方法:当semget创建一个新的信号灯时,信号灯结构semid_ds的sem_otime成员初始化后的值为0 。因此,第二个进程在成功调用semget后,可再次以IPC_STAT命令调用semctl,等待sem_otime变为非0值,此时可判断该信号灯已经初始化完毕 。下图描述了竞争状态产生及解决方法:
推荐阅读
- 红茶时间越久越好吗,普洱茶生茶判别
- 神舟十一号飞船的发射时间 神舟十号飞船发射火箭返回时间
- 凤凰山ufo神秘事件 凤凰山UFO事件
- 立冬下雨好还是天晴好?
- 一天最佳三个运动时间是何时?
- 空间站|天舟三号从空间站后端绕前端对接:将迎接天舟四号、神舟十四号载人飞船
- 面试官:知道时间轮算法吗?在Netty和Kafka中如何应用的?
- 灵异真实故事民间 灵异民间故事
- 启元世界:打造AI决策智能体,用小样本实现10的26次方复杂空间决策
- 2021年中国空间站计划 我国空间站将在2022年前后建成并运营
