信号量(System V)

本文详细介绍信号量集的创建、操作及控制等核心函数semget、semop和semctl的使用方法,包括各函数参数含义、返回值及应用场景,并提供实例帮助理解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. semget

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

信号量集被建立的情况有两种:
1.如果键的值是IPC_PRIVATE
2.键的值不是IPC_PRIVATE,并且键所对应的信号量集不存在,同时标志中指定IPC_CREAT

flag:
1.单独使用IPC_CREAT,要么返回新创建的信号量集的标识符,要么返回系统中已经存在的同样的关键字值的信号量的标识符
2.IPC_EXCL和IPC_CREAT一同使用,要么返回新创建的信号量集的标识符,要么返回-1
3.IPC_EXCL单独使用没有意义

nsems:新的信号量集中应该创建的信号量的个数(最多的信号量的个数在linux/sem.h中定义)

struct semid_ds
{
    struct ipc_perm     sem_perm;
    unsigned short      sem_nsems;     /* # of semaphore in set */
    time_t              sem_otime;     /* last-semop() time */
    time_t              sem_ctime;     /* last-change time */
    …
};
struct ipc_perm
{
    uid_t      uid;        /* owner’s effective user id */
    gid_t      gui;        /* owner’s effective group id */
    uid_t      cuid;       /* creator’s effective user id */
    gid_t      cgid;       /* creator’s effective group id */
    mode_t     mode;       /* access mode */
    …
};

如果是创建一个新的信号量集合,那么对semid_ds的成员进行初始化

1.ipc_perm中的mode被设置为flag中的相应权限位
2.sem_nsems设置为nsems
3.sem_otime设置为0
4.sem_ctime设置为当前时间

注意:如果创建新集合, 则必须指定nsems, 如果引用一个集合, 则nsems设定为0

2. semop

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

struct sembuf
{
    unsigned short sem_num; /* semaphore number */
    short sem_op; /* semaphore operation */
    short sem_flg; /* operation flags */
};

sem_num:操作信号在信号集中的编号,第一个信号的编号是0

sem_op:
1.如果sem_op是正数,则信号量加上它的值
2.如果sem_op是负数,那么信号量将减去它的值,如果没有使用>IPC_NOWAIT,操作将会阻塞,直到信号量控制的资源可以使用为止,通常用于获取资源的使用权
3.如果sem_op是0,操作将暂时阻塞,直到信号量的值为0,这在一个进程等待完全空闲的资源时使用

sem_flg:
1.IPC_NOWAIT //对信号的操作不能满足时,semop()不会阻塞,并立即返回,同时设定错误信息
2.SEM_UNDO //程序结束时(不论正常或不正常),保证信号值会被重设为semop()调用前的值。这样做的目的在于避免程序在异常情况下结束时未将锁定的资源解锁,造成该资源永远锁定(如果为sem_flg指定SEM_UNDO,Linux会在进程退出的时候自动撤销该次操作)

nsops:信号操作结构的数量

3. semctl

int semctl(int semid, int semnum, int cmd, … /* union semun arg */)

union semun
{
    int                  val;         /* for SETVAL */
    struct semid_ds      *buf;       /* for IPC_STAT and IPC_SET */
    unsigned short       *array;    /* for GETALL and SETALL */
};
//无名结构体
struct {
    unsigned short              semval;   /* semaphore value, always >= 0 */
    pid_t                       sempid;   /* pid for last operation */
    unsigned short              semncnt; /* # processes awaiting semval>curval */
    unsigned short              semzcnt; /* # processes awaiting semval == 0 */
    …
};

cmd包括十种命令:
1.IPC_STAT
读取semid_ds到arg.buf
2.IPC_SET
将arg.buf设置到sem_perm.uid, sem_perm.gid和sem_perm.mode
3.IPC_RMID
将信号量集从内存中删除
4.GETVAL
返回semnum信号量的无名结构体的成员semval值
5.SETVAL
arg.val设置到由semnum信号量的无名结构体成员semval中
6.GETPID
返回无名结构体成员sempid,最后一个执行semop操作的进程的PID
7.GETNCNT
返回无名结构体成员semncnt,正在等待资源的进程数目
8.GETZCNT
返回无名结构体成员semzcnt,等待完全空闲的资源的进程数目
9.GETALL
取该集合中所有信号量(无名结构体)的值, 存放在arg.array指向的数组中
10.SETALL
将arg.array指向的数组的值设置该集合所有信号量的值(无名结构体)

:semctl中的最后一个参数是一个联合类型的副本,而不是一个指向联合类型的指针
error详见百科

[test@localhost ~]$ ipcs -s
------ Semaphore Arrays --------
key        semid      owner      perms      nsems 
0x0000eeee 1310730    test       660        2  
key: semget中的key
semid: semget中创建成功返回值
owner: 创建者用户名
perms: semget中的flag
nsems: semget中的nsems (和semop中sops.sem_num息息相关,如果指定为1,sem_num只能操作一个信号量集)

4. 查看更详细信息

# ipcs [-s -m -q] -i id
# ipcs -s -i 32769     

Semaphore Array semid=32769
uid=0    gid=0   cuid=0  cgid=0
mode=0600, access_perms=0600
nsems = 1
otime = Sun Aug 16 02:31:22 2015  
ctime = Sun Aug 16 02:31:07 2015  
semnum     value      ncount     zcount     pid       
0          1          0          0          835  

5. 例子

int main()
{
    int ret = 0;
    int semid = 0;
    printf("%p\n", IPC_CREAT);
    semid = semget(key, 2, IPC_CREAT | 0666);
    if(semid < 0)
    {
        perror("semget");
    }
    struct sembuf sembuf[3] = {0};
    sembuf[0].sem_num = 1;
    sembuf[0].sem_op = 1;
//  sembuf[0].sem_flg = SEM_UNDO;   //4096
    sembuf[0].sem_flg = IPC_NOWAIT; //2048

    ret = semop(semid, sembuf, 1);
    if(ret < 0)
    {
        perror("semop");
    }

    sembuf[0].sem_num = 1;
    sembuf[0].sem_op = -2;
    sembuf[0].sem_flg = 0;
    ret = semop(semid, sembuf, 1);
    if(ret < 0)
    {
        perror("semop");
    }

    semctl(semid, 1, IPC_RMID);

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值