linux中的semop和semctl函数

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参数,但是在这里,对于每个信号量进行的操作需要一个结构体的所有属性(三个)共同指定、共同完成。
    struct sembuf{
    unsigned short sem_num;  /* semaphore number */
    short          sem_op;   /* semaphore operation */
    short          sem_flg;  /* operation flags */
    }
    
    sembuf属性释义:
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_permThis is an ipc_perm structure (see below) that specifies the access permissions on the semaphore set.
    sem_otimeTime of last semop(2) system call.
    sem_ctimeTime of creation of semaphore set or time of last semctl() IPCSET, SETVAL, or SETALL operation.
    sem_nsemsNumber 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
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
semctl函数Linux系统用于对信号量进行控制操作的系统调用函数函数原型: ```c #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> int semctl(int semid, int semnum, int cmd, ...); ``` 参数说明: - `semid`:信号量集标识符; - `semnum`:信号量的编号,从0开始; - `cmd`:控制命令,可以是IPC_RMID(删除信号量集)、IPC_SET(设置信号量集的IPC权限)、IPC_STAT(获取信号量集的状态信息)、GETVAL(获取信号量的值)、SETVAL(设置信号量的值)、GETPID(获取上次执行semop操作的进程ID)、GETNCNT(获取等待该信号量变为非0的进程数)、GETZCNT(获取等待该信号量变为0的进程数); 如果cmd为IPC_SET,则需要传递一个union semun类型的参数。semun结构定义如下: ```c union semun { int val; /* SETVAL命令使用的信号量值 */ struct semid_ds *buf; /* IPC_STAT和IPC_SET命令使用的结构体指针 */ ushort *array; /* GETALL和SETALL命令使用的数组指针 */ }; ``` 函数返回值为执行结果,通常为0表示执行成功,否则表示执行失败。 常用的控制命令如下: - `IPC_RMID`:删除信号量集; - `IPC_SET`:设置信号量集的IPC权限; - `IPC_STAT`:获取信号量集的状态信息; - `GETVAL`:获取信号量的值; - `SETVAL`:设置信号量的值。 需要注意的是,当使用IPC_RMID命令删除一个信号量集时,如果有其他进程正在使用该信号量集,那么这些进程将会收到一个SIGINT信号,即如同按下了Ctrl+C键一样。因此,在删除信号量集之前,需要确保没有其他进程正在使用该信号量集。 另外,当使用SETVAL命令设置信号量的值时,需要将union semun类型的参数的`val`字段设置为要设置的值。而当使用GETVAL命令获取信号量的值时,需要将union semun类型的参数的`buf`字段设置为一个`semid_ds`结构体指针,用于存放获取的值。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值