semop
https://man7.org/linux/man-pages/man2/semop.2.html
函数简介:
- 名称:
semop, semtimedop - System V semaphore operations
- 所在库:Standard C library (libc, -lc)
- 形式:
每个在信号量集中的信号都有如下属性#include <sys/sem.h> int semop(int semid, struct sembuf *sops, size_t nsops);
理解信号量集(semaphore set):可以理解为一个semaphore 数组,而其中的每个semaphore都是一个结构如下的结构体:struct semaphore{ unsigned short semval; /* semaphore value 信号值 */ unsigned short semzcnt; /* # 等待零 */ unsigned short semncnt; /* # 等待增加 */ pid_t sempid; /* 上次修改信号量值的进程的 PID */ }
函数参数:
struct sembuf *sops
:
对 semid 指示的集合中的选定信号量执行操作。 参数struct sembuf *sops
指向的数组中的每个元素都是一个结构体,用于指定要在单个信号量上执行的操作。
理解“操作是一个结构体”:在以前,操作可能就由一个字符或者一个参数就能表达,例如数值运算的+-*/
,或者IPC_CREAT
参数,但是在这里,对于每个信号量进行的操作需要一个结构体的所有属性(三个)共同指定、共同完成。
sembuf属性释义:struct sembuf{ unsigned short sem_num; /* semaphore number */ short sem_op; /* semaphore operation */ short sem_flg; /* operation flags */ }
sem_flg = {IPC_NOWAIT, SEM_UNDO} |
---|
SEM_UNDO:当进程终止时自动结束该结构体指定的操作 |
sops 中包含的操作集按数组顺序自动执行,也就是说,操作要么作为一个完整的单元执行,要么根本不执行。 如果不能立即执行所有操作,则系统调用的行为取决于各个sem_flg字段中是否存在 IPC_NOWAIT 标志 |
sem_num,指定操作元素 |
---|
每个sembuf 结构体指定的操作都在信号量集的第sem_num 个元素上实现,从0开始。 |
sem_op = {正数,0,负数},指定具体操作 |
---|
正数:操作为,将该sem_op加给该信号量的信号值semval 。此外,如果为此操作指定了sem_flag=SEM_UNDO ,系统将从此信号量的semaphore adjustment(semadj) 值中减去sem_op 的值。(这段没读懂) 此操作始终可以继续 ——它永远不会强制线程等待。 调用进程必须对信号量集具有更改权限。 |
0:该进程必须对该信号量集“可读”。 具体操作为,一旦semaphore的semval=0 ,该操作可以立刻执行;否则,如果sem_flag = IPC_NOWAIT ,semop()失败,errno 设置为 EAGAIN(并且不执行sops 数组中的任何操作)。否则,semzcnt (等待此信号量的值变为零的线程计数)将递增 1,线程将休眠,直到发生以下情况之一: |
负数:semval>=|sem_op|时:semval -= |sem_op|;semval < |semop|时:semncnt += 1,线程睡眠直到如下情况发生:TODO,但若设置sem_flag=IPC_NOWAIT,则函数运行失败,返回错误 |
• semval becomes greater than or equal to the absolute value of
sem_op: the operation now proceeds, as described above.
• The semaphore set is removed from the system: semop() fails,
with errno set to EIDRM.
• The calling thread catches a signal: the value of semncnt is
decremented and semop() fails, with errno set to EINTR.
每个信号的sempid
:成功完成semop()
后,sops
参数指向的数组中指定的每个信号灯的 sempid
值将设置为调用方的进程 ID。
- 返回值:
- 成功:返回0;
- 失败,范围-1,并设置errno
- 错误类型
注释: semadj
:semadj值是每个进程都有,且互不相同的整数,它是在指定SEM_UNDO标志的信号量上执行的所有操作的否定总和。 每个进程都有一个 semadj 值列表——每个使用SEM_UNDO操作的信号量都有一个值。 当进程终止时,其每个信号量 semadj 值都会添加到相应的信号量中,从而撤消该进程的操作对信号量的影响(但请参阅下面的 BUGS)。 当使用 SETVAL 或 SETALL 请求直接设置 semctl(2) 的信号量值时,所有进程中对应的 semadj 值都会被清除。 clone(2) CLONE_SYSVSEM 标志允许多个进程共享一个 semadj 列表;详见 clone(2)。
示例
以下代码段使用semop()
自动等待信号量0值的到来,到来后信号量值加一。
struct sembuf sops[2];
int semid;
/* Code to set semid omitted */
sops[0].sem_num = 0; /* Operate on semaphore 0 */
sops[0].sem_op = 0; /* Wait for value to equal 0 */
sops[0].sem_flg = 0;
sops[1].sem_num = 0; /* Operate on semaphore 0 */
sops[1].sem_op = 1; /* Increment value by one */
sops[1].sem_flg = 0;
if (semop(semid, sops, 2) == -1) {
perror("semop");
exit(EXIT_FAILURE);
}
~~
semctl
https://man7.org/linux/man-pages/man2/semctl.2.html
简介
- 名称:semctl - System V semaphore control operations
- 形式
#include <sys/sem.h>
int semctl(int semid, int semnum, int cmd, ...);
- 功能:semctl()根据
cmd
参数对V操作中由semid
指定的信号量集进行操作,或对信号量集中的第semnum
信号操作(从0开始编号)
参数
根据cmd
的值,函数可能有3个或4个参数。第四个参数为union semun
,定义如下:
union semun {
int val; /* Value for SETVAL */
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO
(Linux-specific) */
};
semid_ds
结构体在<sys/sem.h>
中定义:
以上结构体成员的含义:struct semid_ds { struct ipc_perm sem_perm; /* Ownership and permissions */ time_t sem_otime; /* Last semop time */ time_t sem_ctime; /* Creation time/time of last modification via semctl() */ unsigned long sem_nsems; /* No. of semaphores in set */ };
sem_perm This is an ipc_perm structure (see below) that specifies the access permissions on the semaphore set. sem_otime Time of last semop(2) system call. sem_ctime Time of creation of semaphore set or time of last semctl() IPCSET, SETVAL, or SETALL operation. sem_nsems Number of semaphores in the set. Each semaphore of the ipc_perm
:
其中的struct ipc_perm { key_t __key; /* Key supplied to semget(2) */ uid_t uid; /* Effective UID of owner */ gid_t gid; /* Effective GID of owner */ uid_t cuid; /* Effective UID of creator */ gid_t cgid; /* Effective GID of creator */ unsigned short mode; /* Permissions */ unsigned short __seq; /* Sequence number */ };
mode
参数定义了对共享内存的access permission,如下:
0400 Read by user
0200 Write by user
0040 Read by group
0020 Write by group
0004 Read by others
0002 Write by others
事实上,对信号量集来说,“write” 等同于"alter" 。Bits 0100, 0010和0001 (the execute bits) 并未使用到。
cmd的值
- IPC_RMID:删除该信号量集,唤醒所有被semop()阻塞的进程。
- GETALL:返回所有信号量的值,存储在一个数组arg.array中。参数
semnum
被忽视。此时调用进程必须对信号量集具有可读权限。 - GETNCTNT:返回该信号量集的第
semnum
个信号的semncnt
。 - GETPID:返回该信号量集的第
semnum
个信号的sempid
。这是最后一次使用该信号的进程的PID。 - GETVAL:返回该信号量集的第
semnum
个信号的semval
, - SETALL:设置信号量集中所有信号量的值,用一个数组arg.array