结构体的定义如下:
1. struct sembuf
2. {
3. short int sem_num; /* 信号量的序号从0~nsems-1 */
4. short int sem_op; /* 对信号量的操作,>0, 0, <0 */
5. short int sem_flg; /* 操作标识:0, IPC_WAIT, SEM_UNDO */
6. };
sem_num标识信号量集中的第几个信号量,0表示第1个,1表示第2个,nsems - 1表示最后一个。
sem_op标识对信号量的所进行的操作类型。对信号量的操作有三种类型:
- sem_op > 0,对该信号量执行挂出操作,挂出的值由sem_op决定,系统会把sem_op的值加到该信号量的当前值semval(参考文章开头关于每个信号量结构的定义)上。如果sem_flag指定了SEM_UNDO(还原)标志,那么相应信号量的semadj值会减掉sem_op的值。下面会说明semadj的含义。
- sem_op < 0,对该信号量执行等待操作,当信号量的当前值semval >= -sem_op时,semval减掉sem_op的绝对值,为该线程分配对应数目的资源。如果指定SEM_UNDO,相应信号量的semadj就加上sem_op的绝对值。当semval < -sem_op时,相应信号量的semncnt就加1,调用线程被阻塞,直到semval >= -sem_op,当此条件满足时,调用线程被唤醒,执行相应的分配操作,然后semncnt减去1.
- sem_op = 0,表示调用者希望semval变为0。如果为0则立即返回,如果不为0,相应信号量的semzcnt加1,调用调用线程被阻塞。
sem_flag:信号量操作的属性标志,如果为0,表示正常操作,如果为IPC_WAIT,使对信号量的操作时非阻塞的。即指定了该标志,调用线程在信号量的值不满足条件的情况下不会被阻塞,而是直接返回-1,并将errno设置为EAGAIN。如果为SEM_UNDO,那么将维护进程对信号量的调整值,以便进程结束时恢复信号量的状态。
下面解释一下与单个信号量相关的几个值:
semval:信号量的当前值,在文章开头信号量的结构中已提到。
semncnt:等待semval变为大于当前值的线程数。在文章开头信号量的结构中已提到。
semzcnt:等待semval变为0的线程数。在文章开头信号量的结构中已提到。
semadj:指定信号量针对某个特定进程的调整值。只有sembuf结构的sem_flag指定为SEM_UNDO后,semadj才会随着sem_op而更新。讲简单一点:对某个进程,在指定SEM_UNDO后,对信号量semval值的修改都会反应到semadj上,当该进程终止的时候,内核会根据semadj的值,重新恢复信号量之前的值。