System V 信号量使用相关函数

System V 信号量

在提到Posix 信号量时,指的是二值信号量或计数信号量,而System V信号量指的是入了计数信号量集

二值信号量:其值为0或1,类似于互斥锁,资源被锁住时为0,资源可用为1
计数信号量:其值在0和某个限制值之间的信号量,信号量的值就是可用资源数
计数信号量集:一个或多个信号量构成一个集合,集合中每个元素都是计数信号量(每个集合的信号量数存在一个限制)

semid_ds结构:

内核为每个信号量集维护的信息结构

#include <sys/sem.h>

struct semid_ds{
    struct ipc_perm sem_perm;   // 当前信号量的访问权限
    struct sem *sem_base;        // 内核用于维护某个给定信号量的一组值的内部数据结构
    ushort sem_nsems;           // 集合中信号量的数目
    time_t sem_otime;           // 最近一次执行semop()的时间
    time_t sem_ctime;           // 集合创建时间或最近一次IPC_SET的时间
};

struct sem{
    ushort_t semval;    // 信号量实际值
    short sempid;       // 对信号量值执行最后一次操作的进程的进程ID
    ushort_t semncnt;   // 等待信号量值增长的进程数
    ushort_t semzcnt;   // 等待信号量值变为0的进程数
};

semget()函数:

#include <sys/sem.h>

// 创建一个信号量集或访问一个已存在的信号量集
// 成功返回非负信号量标识符,出错返回-1
int semget(key_t key, int nsems, int oflag);
// key: IPC 键
// nsems:指定集合中信号量数
// oflag:SEM_R(读)和SEM_A(改)的组合,还可以按位与IPC_CREAT或IPC_CREAT|IPC_EXCL

semop()函数:

#include <sys/sem.h>

// 对信号量集中一个或多个信号量进行操作
// 成功返回0,出错返回-1
int semop(int semid, struct sembuf *opsptr, size_t nops);
// semid:由semget()函数返回的信号量标识符
// nops: 指出opsptr指向的结构数组的元素数量
// opsptr:指向一个如下的数组

struct sembuf{
    short sem_num;  // 信号量集中信号量的索引值:0, 1, ... , nsems-1(sem_base[sem_num], 指定对某个特定信号量进行操作)
    short sem_op;   // 指定对特定信号量的操作
    short sem_flg;  // 操作标志,0, IPC_NOWAIT、SEM_UNDO
};
// sembuf结构内元素的排列顺序并不保证如上述那样,只保证该结构中有上述三个元素
// sembuf结构不能静态初始化(struct sembuf value = {0, 0, 0} // Error)
// sembuf结构需要运行时初始化(struct sembuf value; value.sem_num = 0; ...)

// sem_op:每个特定的操作有sem_op确定,它可以是负数、0、正数
// sem_op为正数时,其值加到semval(信号量当前值)上,对应于释放信号量控制的资源
//       如果指定了SEM_UNDO标志,就从相应信号量的semadj(所指定信号量针对调用进程的调整值)减去sem_op
// sem_op为0,调用者等待semval变为0,如果semval已经为0,则立即返回
// sem_op为负数,调用者希望等待semval变为大于或等于sem_op的绝对值,这对应于分配资源

semctl()函数:

#include <sys/sem.h>

// 对一个信号量执行各种控制操作
// 成功返回非负值,出错返回-1
int semctl(int semid, int semnum, int cmd, ... /* union semun arg */);
// semid: 标识其操作待控制的信号量集
// semnum: 标识信号量集内的某个成员(sem_base[sem_num])

// cmd:可选值如下(除非另外说明,操作成功函数返回值为0,出错为-1)
// GETVAL:将semval的当前值作为函数返回值返回
// SETVAL:将semval设为arg.val(若操作成功,那么相应信号量的semadj被设为0)
// GETPID:将sempid的当前值作为函数返回值返回
// GETNCNT:将semncnt(等待semval变为大于其当前值的线程数)的当前值作为函数返回值返回
// GETZCNT:将semzcnt(等待semval变为0的线程数)的当前值作为函数返回值返回
// GETALL:返回指定信号量集内每个成员的semval值(这些值通过arg.array指针返回)
// SETALL:设置指定信号量集内每个成员的semval值(这些值通过arg.array指针传递)
// IPC_RMID:将由semid指定的信号量集从系统删除
// IPC_SET:设置指定信号量集的semid_ds结构中的sem_perm.uid、sem_perm.gid、sem_perm.mode,这些值由arg.buf参数指向的结构中的相应成员指定
// IPC_STAT:返回指定信号量集当前的semid_ds结构(通过arg.buf)

// arg: 可选参数,根据 cmd 参数而定
union semun{
    int val;
    struct semid_ds *buf;
    ushort *array;
};
原文地址:https://www.cnblogs.com/lnlin/p/9741943.html