59-System V 信号量(简介)

不同于 System V 共享内存和消息队列,这两者都是用于交换数据,而 System V 信号量通常用来做进程同步。

1. System V 信号量简介

准确的说 System V 信号量应该叫 System V 信号量集,因为它可以同时操作多个信号量。多个信号量保存在数组中。

你可以把信号量理解成一种资源数量,当你使用这种资源的时候,信号量的值就会减少,当你归还资源的时候,信号量的值就增多。在信号量中,使用资源和归还资源,有一套函数可以进行控制,这种函数要么一次成功,要么就失败,也就是原子操作。如果资源用完了,你还去请求资源,进程就会阻塞。

比如说有 5 个蛋糕,与它对应的信号量为 sem,它的值为 5,当多个进程使用 P(sem)函数(消费一个蛋糕)的时候,P(sem)要么一次全部执行完,要么就不执行。绝对不可能出现 P(sem) 执行到一半的时候,另一个进程也执行到 P(sem) 当中。换句话说,蛋糕资源,同时只能被一个进程申请,只有一个进程申请完成后,其它进程才有机会申请。

有人会问,直接使用 sem-- 操作不好吗?不好不好,sem– 它不是原子操作,因为执行到一半的时候,就有可能被切换到另一个进程中去,这会导致竞争错误。sem--的汇编指令如下:

mov eax, sem
sub eax, 1
mov sem, eax

本质上sem--是由3条汇编指令构成的,所以这根本不是原子操作,除非有一种机制能保存这 3 条汇编语句一次完成。而信号量就做了类似的工作,它可以让一系列的指令要么一次全部执行完成,要么一条都不执行。

借助信号量,可以实现传说中的生产者消费者程序,可以提前预览一下效果:


这里写图片描述
图1 生产者(左)与消费者(右边两个)

图1 中的生产者生产蛋糕,而右边有两个者消费蛋糕。这个程序后面会讲,这里只是让大家有一个直观的感受。

2. 与 System V 信号量有关的函数

 int semget(key_t key, int nsems, int semflg);
 int semop(int semid, struct sembuf *sops, unsigned nsops);
 int semctl(int semid, int semnum, int cmd);
 int semctl(int semid, int semnum, int cmd, union semun buf);

相比共享内存和消息队列,操作信号量的函数要少一些,常用的就这 3 个,但是,使用的难度却更大了。(注意最后两个都是同一个函数,只是参数个数不同,semctl 是一个可变参数函数)。

为了尽快掌握这几个函数,先大致了解一下几个参数。

  • semget 中的参数 nsems,表示你要创建几个信号量(即几个资源)。创建完成后,以后要操作哪个信号量,只要告诉信号量的索引号就行了。
  • semctl 中的 semnum 参数,表示要操作哪个信号量,这就是信号量的索引号。
  • semop 中的 sops 参数,该参数需要传递一个数组,nsops 表示数组的个数。数组元素是 sembuf 结构体,该结构体中封装了请求还是归还信号量,以及操作哪个信号量,以及操作信号量的行为特性。具体如下:
struct sembuf {
    unsigned short sem_num;  /* 要操作的信号量索引 */
    short          sem_op;   /* > 0 归还资源数,< 0 请求资源数 */
    short          sem_flg;  /* 可选项,操作的行为 */
}
  • semctl 中的 union semun buf 参数,该参数依赖于 cmd 命令,具体如下:
union semun {
    int              val;    /* cmd = SETVAL */
    struct semid_ds *buf;    /* cmd = IPC_STAT, IPC_SET */
    unsigned short  *array;  /* cmd = GETALL, SETALL */
};

以上只是大致介绍,后面会细讲。

3. 如何使用信号量

信号量的常用的使用主要有下面几个步骤,具体可以根据需要而调整。

  • 指定要创建的信号量的个数,创建信号量的 ipc 内核对象,获取 ipc 内核对象 id.
  • 使用 semctl 的 SETVAL 或者 SETALL 命令设置信号量的值(每种资源的个数)。
  • 使用 semop 对指定若干个信号量进行同时操作(请求资源或归还资源)。
  • 使用 semctl 的 IPC_RMID 命令删除信号量

4. 总结

  • 理解信号量可以干什么
  • 理解信号量和前面学的共享内存和消息队列的差异性

练习:尝试创建一个信号量 ipc 内核对象,并使用 semctl 的 IPC_STAT 命令打印其信息,然后删除它。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值