IPC通信-信号量

信号量SEM全称Semaphore,中文也翻译为信号灯,如图5-13所示。作为system-V IPC 的最后一种,信号量跟前面的 MSG 和 SHM 有极大的不同,SEM 不是用来传输数据的, 而是作为“旗语”,用来协调各进程或者线程工作的。下面分三部分来解剖他。

 

Linux 中用到的信号量有 3 种:ststem-V 信号量、POSIX 有名 信号量和 POSIX 无名信号量(详见 5.5)。他们虽然有很多显著不同 的地方,但是最基本的功能是一致的:用来表征一种资源的数量,当多个进程或者线程争夺这些稀缺资源的时候,信号量用来保证他们合理 地、秩序地使用这些资源,而不会陷入逻辑谬误之中。


用一个司空见惯的例子来说明什么是“旗语”——红绿灯,在 图 5-13 红绿灯 一个繁忙的十字路口,稀缺资源就是通过十字路口的权限,为了避 免撞车规定每次只能是对开方向的车通过路口不能转弯),此时另外两个方向的车必须停下 来等待,直到红绿灯变换为止。

一些基本概念如下:

1,多个进程或线程有可能同时访问的资源(变量、链表、文件等等)称为共享资源, 也叫临界资源(critical resources)。

2,访问这些资源的代码称为临界代码,这些代码区域称为临界区(critical zone)。

3,程序进入临界区之前必须要对资源进行申请,这个动作被称为 P 操作,这就像你要 把车开进停车场之前,先要向保安申请一张停车卡一样,P 操作就是申请资源,如果申请成 功,资源数将会减少。如果申请失败,要不在门口等,要不走人。

4,程序离开临界区之后必须要释放相应的资源,这个动作被称为 V 操作,这就像你把 车开出停车场之后,要将停车卡归还给保安一样,V 操作就是释放资源,释放资源就是让资 源数增加。

所有一起访问共同临界资源的进程都必须遵循以上游戏规则,否则大家就都乱套了,但 是值得注意的是:这些规则是自愿的,如果有进程就是胡来——在访问资源之前不申请,那 么将会可能导致逻辑谬误,就像开车压死保安直接撞进停车场一样,虽然于情于理都不可以, 物理上阻止不了这种行为。

system-V 的信号量非常类似于停车场的卡牌,想象一个有 N 个车位的停车场,每个 车位是立体的可升降的,能停 n 辆车,那么我们可以用一个拥有 N 个信号量元素,每个信 号量元素的初始值等于 n 的信号量来代表这个停车场的车位资源——某位车主要把他的 m 辆车开进停车场,如果需要 m 个车位,那么必须对代表这个车位的信号量元素申请资源, 如果 n大于等于 m,则申请成功,否则不能把车开进去。

从这个比喻中得知:system-V 的信号量并不是单个的值,而是一组(事实上是一个数 组)信号量元素构成的,当我们需要多个资源,比如多个车位时,可以同时向多个信号量元 素申请。

信号量的 P、V 操作最核心的特征是:他们是原子性的,也就是说对信号量元素的值的 增加和减少,系统保证在 CPU 的电气特性级别上不可分割,这跟整型数据的加减法有本质 的区别。

API 接口:

创建信号量时,还受到以下系统信息的影响:

1,SEMMNI:系统中信号量的总数最大值。

2,SEMMSL:每个信号量中信号量元素的个数最大值。

3,SEMMNS:系统中所有信号量中的信号量元素的总数最大值。

Linux 中,以上信息在/proc/sys/kernel/sem 中可查看。

申请P、释放V 信号量:

使用以上函数接口需要注意以下几点:

1,信号量操作结构体的定义如下:

struct sembuf { 
    unsigned short sem_num; /* 信号量元素序号(数组下标) */ 
    short sem_op; /* 操作参数 用来确定是 P(<0) 或 V(> 0 ) 操作*/ 
    short sem_flg; /* 操作选项 */ 
};

请注意:信号量元素的序号从 0 开始,实际上就是数组下标。

2,根据 sem_op 的数值,信号量操作分成 3 种情况:

A) 当 sem_op 大于 0 时:进行 V 操作(释放资源),即信号量元素的值(semval)将会被加 上 sem_op 的值。如果 SEM_UNDO 被设置了,那么该 V 操作将会被系统记录。V 操 作永远不会导致进程阻塞。

B) 当sem_op等于0时:进行等(等待)零操作,如果此时semval恰好为0,则semop( ) 立即成功返回,否则如果 IPC_NOWAIT 被设置,则立即出错返回并将 errno 设置为 EAGAIN,否则将使得进程进入睡眠,直到以下情况发生:

B1) semval 变为 0。

B2) 信号量被删除。(将导致 semop( )出错退出,错误码为 EIDRM)

B3) 收到信号。(将导致 semop( )出错退出,错误码为 EINTR)

C) 当 sem_op 小于 0 时:进行 P 操作(申请),即信号量元素的值(semval)将会被减 去 sem_op 的绝对值。如果 semval 大于或等于(资源足够) sem_op 的绝对值,则 semop( )立 即成功返回,semval 的值将减去 sem_op 的绝对值(资源量减少),并且如果 SEM_UNDO 被设置 了,那么该 P 操作将会被系统记录。如果 semval 小于 sem_op 的绝对值(资源不足)并且设置了 IPC_NOWAIT,那么 semop( )将会出错返回且将错误码置为 EAGAIN,否则将使得 进程进入睡眠,直到以下情况发生:

C1) semval 的值变得大于或者等于 sem_op 的绝对值(资源再次充足)。

C2) 信号量被删除。(将导致 semop( )出错退出,错误码为 EIDRM)

C3) 收到信号。(将导致 semop( )出错退出,错误码为 EINTR)

使用以上函数接口,需要注意以下几点:

1,这是一个变参函数,根据 cmd 的不同,可能需要第四个参数,第四个参数是一个 如下所示的联合体,用户必须自己定义:

union semun { 
    int val; /* 当 cmd 为 SETVAL 时使用 */ 
    struct semid_ds *buf; /* 当cmd为IPC_STAT 或IPC_SET 时使用 */ 
    unsigned short *array; /* 当 cmd 为 GETALL 或 SETALL 时使用 */ 
    struct seminfo *__buf;/* 当 cmd 为 IPC_INFO 时使用 */ 
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值