欢迎访问我的网站,希望内容对您有用,感兴趣的可以加入我们的社群。

进程间通信之信号量

C/C++ 迷途小书童 6年前 (2019-03-10) 2182次浏览 0个评论

说到底,信号量就是用来控制多个进程对共享资源使用的一个计数器

相关数据结构

1、sem

信号量对象是多个信号量的集合,而这个集合在linux中是以数组的形式实现的,数组的每个成员都是一个单独的信号量,即sem结构

struct
{
    short sempid;   /*最近一次操作信号量的进程的id*/
    unsigned short semval;  /*信号量的计数值*/
    unsigned short semncnt; /*等待使用资源的进程数目*/
    unsigned short semzcnt; /*等待资源完全空闲的进程数目*/
}

2、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 */
    void *__pad;
};

3、sembuf

被用来定义对信号量对象的基本操作

struct sembuf
{
    unsigned short sem_num;     /* 接受操作的信号量在信号量数组中的序号,即数组下标 */
    short        sem_op;        /* 定义了进行的操作,取值正、0和负值 */
    short        sem_flg;       /* 控制操作行为的标志 */
};
  • 如果sem_op值为负,就从指定的信号量中减去相应的值,对应着获取信号量所监控的资源的操作。若sem_flg中没有指定IPC_NOWAIT标志,如果现有的信号量数值小于sem_op的绝对值(表示现有资源少于所需资源),调用semop()的进程就会阻塞直到信号量的数值大于sem_op的绝对值(表示有足够的资源)。

  • 如果sem_op值为正,就在指定的信号量中加上相应的值,这对应着释放信号量所监控的资源的操作。

  • 如果sem_op值为零,调用semop()的进程会被阻塞直到对应的信号量值为0。这操作就是等待信号量所监控的资源被全部使用。利用这个操作可以动态监控资源的使用并调整资源的分配,避免不必要的等待。

4、semid_ds

struct semid_ds
{
    struct ipc_perm    sem_perm;        /* permissions .. see ipc.h */
    __kernel_time_t    sem_otime;        /* 最近一次semop操作的时间 */
    __kernel_time_t    sem_ctime;        /* 信号量对象最近一次改动发生的时间 */
    struct sem    *sem_base;        /* 信号里数组的起始地址 */
    struct sem_queue *sem_pending;        /* 指向还未进行的操作 */
    struct sem_queue **sem_pending_last;    /* 指向最后一个还未进行的操作 */
    struct sem_undo    *undo;            /* undo requests on this array */
    unsigned short    sem_nsems;        /* 信号量数组成员数目 */
};

msqid_ds类似,semid_ds用来储存每个信号量对象的有关信息。

相关函数

1、semget()

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

int semget(key_t key, int nsems, int semflg);

semget建立新的信号量对象或者获取已有对象的标识符。参数semflg与消息队列中的msgflg参数取值一样。参数nsems是信息量对象中信号量的数目,也就是信号量数组成员的个数。/usr/include/linux/sem.h中定义了它的上限

#define SEMMSL  250

2、semop()

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

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

semop()用来改变信号量对象中各个信号量的状态。参数sopssembuf类型的数组,定义了semop()函数所要进行的操作序列;参数nsopssops数组的长度也就是semop()进行的操作个数。

3、semctl()

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

int semctl(int semid, int semnum, int cmd, ...);

semctl()直接来控制信号量对象。semid为信号量对象标识符,semnum信号量在集合中的序号。根据cmd的取值,可带第4个参数,union semun argcmd可取如下值

  • IPC_STAT: 取得semidsemid_ds信息,并存放在argbuf
  • IPC_SET: 用arg中的buf设定信号量对象的semid_ds结构
  • IPC_RMID: 删除信号量对象
  • GETALL: 取得信号量对象所有信号量的值,并存放在argarray中返回
  • GETNCNT: 返回正在等待使用某个信号量所控制的资源的进程数目
  • GETPID: 返回最近一个对某个信号量调用semop()的进程的pid
  • GETVAL: 返回集合中最后一个信号量的semval
  • GETZCNT: 返回正在等待某个信号量所控制资源被全部使用的进程数目
  • SETALL:用argarray来设定对象内处个信号量的值
  • SETVAL: 用argval的值来设定对象中某个信号量的值
喜欢 (0)

您必须 登录 才能发表评论!