【Linux】进程间通信(信号量 Semaphore)

本文详细介绍了Linux中进程间通信的重要机制——信号量Semaphore,包括信号量的概念、作用、原理及操作函数。通过实例解析了如何使用信号量实现进程同步,避免了临界资源的竞争问题。
摘要由CSDN通过智能技术生成

前言:进程同步篇

前一节学习了管道完成进程间通信(IPC),其主要机制就是使用虚拟文件系统(VFS)的管道文件的半双工的通信。

为什么需要进行进程同步?进程异步不是效率更高吗?
因为牵扯到两个概念

两个概念:

  • 临界资源:同一时刻,只允许一个进程或者线程访问的资源(打印机等)
  • 临界区:访问临界资源的代码段(p和v操作之间的代码,尽量减少代码量,代码量过多会导致p操作阻塞,影响程序执行效率)
  • 原子操作:不能被终止的,一旦开始操作,必须等待操作完成(申请临界资源的操作)

举个栗子(一定要看!!!)

一个试衣间,是不是在某个时刻只能被一个人使用呢?答案是肯定的,此时的一个试衣间就算是临界资源;那你在试衣间干什么?那废话,肯定试衣服了,此时的试衣服的过程就算是临界区,那为什么在试衣间换衣服的过程就是临界区呢?折磨说吧,你(进程a)进入试衣间正在换衣服,秃然之间,有个猥琐大汉(进程b)闯进了你的试衣间,那是不是完蛋了。所以你在使用试衣间(临界资源)之前,肯定要反锁(P操作),当你换衣完成,出来的时候要开锁(V操作),在你换衣服的整个过程中就是访问临界资源的操作(代码操作临界资源)


(一)信号量

信号量是一个特殊的变量,一般取正数值。代表着允许访问资源的数目。

  • 获取资源时,需要对信号量原子减一,称为p操作(荷兰语passeren)。
  • 释放资源时,需要对信号量原子加一,称为v操作(荷兰语Verhoog)

信号量的内核对象是一个信号量集(信号量的数组)

(二)信号量的作用

作用:主要用于同步进程(进程同步工作)。

  • 二进制信号量:信号量的值如果只取0,1;
  • 计数信号量:信号量的值大于1;

注意:
当进程获取资源时,信号量为0时,进行p操作进程会阻塞;

(三)信号量的能进程通信的原理

请添加图片描述

(四)信号量的操作的函数

所需头文件:

  • sys/types.h
  • sys/ipc.h
  • sys/sem.h
(1)创建或者获取已存在的信号量集

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

  • key:两个进程使用相同的key值,就可以使用同一个信号量
  • nsems:内核维护的是一个信号量集,创建信号量集时,会指定信号量集的信号量个数(数组的大小),获取无所谓
  • semflg:可选IPC_CREAT没有key对应信号量就创建,存在则返回对应的信号量集的ID 、 IPC_EXCL(不管有没有该信号量都返回-1);IPC_CREAT | IP_EXCL没有则创建,有则返回-1
  • 返回值成功返回信号量集的ID,失败返回-1

注意:创建的信号量不手动销毁,系统内核就会一直帮我们维护下去,除非重启系统;

(2)操作信号量(初始化信号量的值、销毁信号量集)

int semctl(int semid, int semnum, int cmd, .../* union semun val*/ )

  • semid:信号量ID
  • semnum:信号量集的下标(操作第几个信号量)
  • cmd:SETVAL(创建) 、 IPC_RMID(销毁)
  • 返回值:成功0,失败-1

union semun联合体的结构体(需要自己声明)(都是4个字节):

union semun
{
    
	int val;				//设置的信号量的值 :临界资源的个数(一个打印机等)
	struct semid_ds *buf; 	//IPC_STAT, IPC_SET的缓冲区
	unsigned short *array;	//GETALL,SETALL的数组
	struct seminfo *__buff;	//IPC_INFO的缓冲区
};
(3) P V操作函数

int semop(int semid, struct sembuf *sops, size_t nsops);
-semid:信号量集ID

  • struct sembuff *sops:指定p/v操作的buff
  • size_t nsops :操作信号量的个数
    //假设我们定义了一个大小为10的信号量集,现在要对其中的下标5下标8信号量进行访问,进行PV操作,则需要修改struct sembuf中的元素;
  • 返回值:
    第二个参数类型:(该类型已经存在sys/sem.h头文件中)
struct sembuf
{
   
           unsigned short sem_num;  /* semaphore number */ 5 / 8
           short          sem_op;   /* semaphore operation */ -1是P操作 +1是V操作
           short          sem_flg;  /* operation flags */IPC_NOWAIT非阻塞、SEM_UNDO阻塞
}

(五)信号量的具体操作

(1)void sem_init();
函数功能:创建/获取信号量集,初始化信号量的值
(2)void sem_p();
函数功能:实现对临界资源的P(-1)操作
(3)void sem_v();
函数功能:实现对临界资源的V(+1)操作
(4)void sem_destroy();
函数功能:销毁创建的信号量集(只销毁一次)

(六)一个进程同步的栗子

(1)未同步之前

jiege的代码:

#include <stdio.h>
#include <unistd.h>
#
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值