semop() - Unix、Linux 系统调用
Tutorials Point


  Unix 初学者指南
  Unix Shell 编程
  高级 Unix
  Unix 有用参考
  Unix 有用资源
  精选阅读

版权所有 © 2014 tutorialspoint



  首页     参考     讨论论坛     关于 TP  

semop() - Unix、Linux 系统调用


previous next AddThis Social Bookmark Button

广告

名称

semop、semtimedop - 信号量操作

语法

 
#include <sys/types.h>
 
#include <sys/ipc.h>
 
#include <sys/sem.h>

int semop(int semid, struct sembuf *sops, unsigned nsops);

int semtimedop(int semid, struct sembuf *sops, unsigned nsops, struct timespec *timeout);

描述

信号量集中每个信号量都具有以下关联值

unsigned short  semval;   /* semaphore value */
unsigned short  semzcnt;  /* # waiting for zero */
unsigned short  semncnt;  /* # waiting for increase */
pid_t           sempid;   /* process that did last op */

semop() 对由 semid 指示的集合中选定的信号量执行操作。由 sops 指向的数组中的每个 nsops 元素都指定要对单个信号量执行的操作。此结构的元素的类型为 struct sembuf,包含以下成员

unsigned short sem_num;  /* semaphore number */
short          sem_op;   /* semaphore operation */
short          sem_flg;  /* operation flags */

sem_flg 中识别的标志为 IPC_NOWAITSEM_UNDO。如果某个操作指定了 SEM_UNDO,则在进程终止时将自动撤消该操作。

sops 中包含的操作集以原子方式执行,也就是说,这些操作同时执行,并且只有在所有操作都可以同时执行时才执行。如果并非所有操作都可以立即执行,则系统调用的行为取决于 sem_flg 的各个字段中是否存在 IPC_NOWAIT 标志,如下所示。

每个操作都对信号量集的第 sem_num 个信号量执行,其中信号量的第一个编号为 0。有三种类型的操作,由 sem_op 的值区分。

如果 sem_op 是正整数,则此操作会将此值添加到信号量值 (semval)。此外,如果为此操作指定了 SEM_UNDO,则系统会更新此信号量的进程撤消计数 (semadj)。此操作始终可以继续进行 - 它永远不会强制进程等待。调用进程必须对信号量集具有更改权限。

如果 sem_op 为零,则进程必须对信号量集具有读取权限。这是一个“等待为零”操作:如果 semval 为零,则操作可以立即继续进行。否则,如果在 sem_flg 中指定了 IPC_NOWAIT,则 semop() 失败,并设置 errnoEAGAIN(并且不执行 sops 中的任何操作)。否则,semzcnt(等待此信号量值变为零的进程计数)加 1,并且进程休眠,直到发生以下情况之一

标签描述
o semval 变为 0,此时 semzcnt 的值减 1。
o信号量集被移除:semop() 失败,并设置 errnoEIDRM
o调用进程捕获信号:semzcnt 的值减 1,并且 semop() 失败,并设置 errnoEINTR
osemtimedop() 调用中指定的 timeout 时间限制到期:semop() 失败,并设置 errnoEAGAIN
如果 sem_op 小于零,则进程必须对信号量集具有更改权限。如果 semval 大于或等于 sem_op 的绝对值,则操作可以立即继续进行:sem_op 的绝对值从 semval 中减去,并且,如果为此操作指定了 SEM_UNDO,则系统会更新此信号量的进程撤消计数 (semadj)。如果 sem_op 的绝对值大于 semval,并且在 sem_flg 中指定了 IPC_NOWAIT,则 semop() 失败,并设置 errnoEAGAIN(并且不执行 sops 中的任何操作)。否则,semncnt(等待此信号量值增加的进程计数器)加 1,并且进程休眠,直到发生以下情况之一
o semval 变为大于或等于 sem_op 的绝对值,此时 semncnt 的值减 1,sem_op 的绝对值从 semval 中减去,并且,如果为此操作指定了 SEM_UNDO,则系统会更新此信号量的进程撤消计数 (semadj)。
o信号量集从系统中移除:semop() 失败,并设置 errnoEIDRM
o调用进程捕获信号:semncnt 的值减 1,并且 semop() 失败,并设置 errnoEINTR
osemtimedop() 调用中指定的 timeout 时间限制到期:系统调用失败,并设置 errnoEAGAIN
成功完成后,由 sops 指向的数组中指定的每个信号量的 sempid 值将设置为调用进程的进程 ID。此外,sem_otime 将设置为当前时间。

semtimedop() 的行为与 semop() 完全相同,只是在调用进程将休眠的情况下,休眠的持续时间受 timeout 参数中传递的 timespec 结构指定的经过时间量的限制。如果指定的期限已到,则 semtimedop() 失败,并设置 errnoEAGAIN(并且不执行 sops 中的任何操作)。如果 timeout 参数为 NULL,则 semtimedop() 的行为与 semop() 完全相同。

返回值

如果成功,semop() 和 semtimedop() 返回 0;否则,它们返回 -1,并由 errno 指示错误。

错误

如果失败,则 errno 将设置为以下值之一
标签描述
E2BIG 参数 nsops 大于 SEMOPM,即每个系统调用允许的最大操作数。
EACCES 调用进程没有执行指定信号量操作所需的权限,并且没有 CAP_IPC_OWNER 功能。
EAGAIN 操作无法立即进行,并且在 sem_flg 中指定了 IPC_NOWAITtimeout 中指定的时间限制已到期。
EFAULT sopstimeout 参数中指定的地址不可访问。
EFBIG 对于某些操作,sem_num 的值小于 0 或大于或等于集合中信号量的数量。
EIDRM 信号量集已移除。
EINTR 在此系统调用中阻塞时,进程捕获了信号。
EINVAL 信号量集不存在,或者 semid 小于零,或者 nsops 的值为非正数。
ENOMEM 某些操作的 sem_flg 指定了 SEM_UNDO,并且系统没有足够的内存来分配撤消结构。
ERANGE 对于某些操作,sem_op+semval 大于 SEMVMX,即 semval 的实现相关的最大值。

注释

进程的 sem_undo 结构不会在 fork(2) 系统调用中继承,但会在 execve(2) 系统调用中继承。

semop() 在被信号处理程序中断后永远不会自动重新启动,无论在建立信号处理程序时 SA_RESTART 标志的设置如何。

semadj 是一个每进程整数,它只是指定了 SEM_UNDO 标志的所有信号量操作的(负)计数。当使用 semctl(2) 对 SETVALSETALL 请求直接设置信号量的值时,所有进程中相应的 semadj 值都会被清除。

可以使用适当的 semctl(2) 调用检索信号量的 semvalsempidsemzcntsemnct 值。

以下信号量集资源限制会影响 semop() 调用

标签描述
SEMOPM 一次 semop() 调用允许的最大操作数 (32)(在 Linux 上,此限制可以通过 /proc/sys/kernel/sem 的第三个字段读取和修改)。
SEMVMX semval 允许的最大值:实现相关 (32767)。
实现对退出时调整最大值 (SEMAEM)、系统范围内的最大撤消结构数 (SEMMNU) 和每个进程的最大撤消条目系统参数没有内在限制。

semtimedop() 首次出现在 Linux 2.5.52 中,随后被反向移植到内核 2.4.22 中。

错误

当进程终止时,其关联的 semadj 结构集用于撤消它使用 SEM_UNDO 标志执行的所有信号量操作的影响。这带来了一个难题:如果这些信号量调整中的一个(或多个)会导致尝试将信号量的值降低到零以下,则实现应该怎么做?一种可能的方法是阻塞,直到所有信号量调整都能够执行。但这却不可取,因为它可能会迫使进程终止阻塞任意长时间。另一种可能性是完全忽略此类信号量调整(有点类似于在为信号量操作指定 IPC_NOWAIT 时失败)。Linux 采用了第三种方法:尽可能地降低信号量值(即降到零)并允许进程终止立即继续进行。

在内核 2.6.x 中,x <= 10,存在一个错误,在某些情况下,它会阻止等待信号量值变为零的进程在该值实际变为零时被唤醒。此错误在内核 2.6.11 中已修复。

符合标准

SVr4、POSIX.1-2001。

参见



previous next Printer Friendly

广告


  

广告



广告