系统编程——IPC信号量集

进程间通信方式(IPC)

进程间通信(Inter process communication,简称IPC)指的是进程之间的信息交换,进程间通信的方式有很多,比如管道通信、信号通信、共享内存、消息队列、信号量组、POSIX信号量等。

进程间通信可以达到数据传输、共享资源、控制进程等目的,方便用户对进程进行控制和管理。

当然,Linux系统中这么多种进程间的通信方式并不是一同出现的,而是在不同时期被设计出来,Linux系统属于类Unix系统,所以Linux系统继承了很多Unix系统的设计,比如Unix系统的System-V版本中就引入了三种进程间通信方式,分别是消息队列、共享内存、信号量组。这三种通信方式也被称为System-V IPC对象。

信号量的概念

Linux系统中一般把类似于信号量之类可能被进程或者线程共同访问资源称为临界资源(Critical Resou。rces),而程序中访问这些临界资源的代码段被称为临界区(Critical Zone)

信号量本质上其实是一个数字(非负整数),用来表示一种资源的数量,当多个进程或者线程争夺这些稀缺资源的时候,可以使用信号量来保证他们合理地、秩序地使用这些资源。

信号量与信号的区别

  信号量是 Semaphore,而信号是 Signal 。
  虽然都可以实现同步和互斥,但是前者是使用信号处理器来进行的,而后者是使用P,V操作来实现的。

信号量的特点

它是一个特殊变量,访问具有原子性。,只允许对它进行等待和发送信号这两种操作。

  • 等待信号量(P)
    当信号量值为0时,程序等待;当信号量值大于0时,信号量减1,程序继续运行。
  • 发送信号量(V)
    将信号量值加1。

工作原理

举个例子,就是两个进程共享信号量sv,一旦其中一个进程执行了P(sv)操作,它将得到信号量,并可以进入临界区,使sv减1。而第二个进程将被阻止进入临界区,因为当它试图执行P(sv)时,sv为0,它会被挂起以等待第一个进程离开临界区域并执行V(sv)释放信号量,这时第二个进程就可以恢复执行。

由于信号量只能进行两种操作等待和发送信号,即P(sv)和V(sv),他们的行为是这样的:

  • P(sv):如果sv的值大于零,就给它减1;如果它的值为零,就挂起该进程的执行
  • V(sv):如果有其他进程因等待sv而被挂起,就让它恢复运行,如果没有进程因等待sv而挂起,就给它加1
  • PV操作也是属于原子操作

创建信号量集

Linux系统中提供了一个名为semget()的函数,利用该函数可以创建或者打开信号量。
image

  • [参数key]:IPC对象的键值。

  • [参数nsems]:信号量集中的信号量元素个数。信号量的元素的数量可以理解为公共资源的种类。

  • [参数semflg]:创建或者打开信号量集的标志,用户可以选择标志IPC_CREAT 或者 IPC_EXCL,另外还可以指定信号量集的权限,权限才用八进制,和open函数类似。

  • [返回值]:函数调用成功,则会返回信号量集的标识符(一个非负整数),函数调用失败,则会返回-1。计数);出错返回-1。

操作信号量集

创建好一个信号量集之后,用户就可以对信号量集中的信号量资源进行PV操作,Linux系统提供了一个名字叫做semop()的函数,用户通过该函数可以实现对信号量进行申请或者释放。
image

  • [参数semid]:要操作的信号量集的标识符ID。(ID可通过semget()函数的返回值得到)

  • [参数sops]:指向一个struct sembuf类型的结构体,一共有三个成员

    struct sembuf
    {
    	unsigned short sem_num;	//信号量集内的信号量的下标,可以通过下标访问信号量集内的某个信号量。
    	short sem_op;			//对选中的信号量的操作
    							//正整数则是释放信号量(V操作)
    							//负整数则是申请信号量(P操作)
    							//0则是等零操作,即阻带等待直到对应的信号量元素的值为零
    	short sem_flg;			//指对选中的信号量的操作标志,常见的标志有IPC_NOWAIT和SEM_UNDO.
    }
    
  • [参数nsops]:指要完成P/V操作的结构体数组的元素个数,利用该参数可以指定要操作多少个信号量

    • 若进行P操作的数量大于信号量的值则会导致阻塞,而V操作永远不会导致阻塞
  • [返回值]:函数调用成功,则返回0,函数调用失败,则返回-1,并会设置对应的错误码,用户可以根据错误码检查错误。

控制信号量集

Linux系统提供了一个名称叫做semctl()的函数接口,用户可以调用该函数接口来实现设置信号量集的属性、获取信号量集的属性、删除信号量集等操作。
image

  • [参数semid]:信号量集的标识符

  • [参数sem_num]:即将要进行操作的信号量的编号,即信号量集合的下标。

  • [参数command]:将要在集合上执行的命令,通常用特定的宏代替:

    • SETVAL:用于初始化信号量为一个已知的值。所需要的值作为联合semun的val成员来传递。在信号量第一次使用之前需要设置信号量。
      eg:初始化时, semctl(semid,0,SETVAL,initsem);

    • IPC_RMID:从内核删除该信号量集合
      eg:删除信号量 semctl(semid,0,IPC_RMID);

    • semun:是一个联合体
      一般用到val,表示要传给信号量的初始值

union semun{  
    int val;  //一般用到val,表示要传给信号量的初始值
    struct semid_ds *buf;  
    unsigned short *array;  
    struct seminfo *__buf;
};
posted @   藍桉未遇釋槐鳥  阅读(19)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
点击右上角即可分享
微信分享提示