POSIX 信号量

POSIX 信号量是一种 POSIX 标准中定义的进程间同步和互斥的方法。它允许进程之间通过信号量来实现临界区的互斥访问,从而避免竞争条件和死锁等问题。

信号量的P、V操作:

  • P 操作:用于申请信号量资源。如果信号量的值大于 0,则将信号量的值减 1,表示占用一个资源;如果信号量的值等于 0,则进程将被阻塞等待,直到信号量的值大于 0。
  • V 操作:用于释放信号量资源。当一个进程占用资源完成后,使用 V 操作来释放资源,将信号量的值加 1。
  • P 操作和 V 操作都是原子操作,确保在并发环境下资源能正确访问。

POSIX信号量有两种:有名信号量(Named Semaphores)和无名信号量(Unnamed Semaphores)。

有名信号量

有名信号量是通过一个 IPC 名字(一般以斜杠开头的路径名)进行进程间的同步。不同进程通过访问该名字来操作同一个信号量,从而实现对临界区的互斥访问。

IPC 名字:类似 "/mySem" 的字符串,当信号量创建成功后,会在 /dev/shm目录下创建一个特殊的文件。

创建、打开信号量

sem_open() 函数是用于创建或打开一个有名信号量,该函数定义如下:

#include <semaphore.h>

sem_t *sem_open(const char *name, int oflag,
      mode_t mode, unsigned int value);

参数说明

  • name:指定有名信号量的名称(为了跨平台,最好以斜杠开头)。
  • oflag:指定打开有名信号量的标志。有以下取值:
    • O_CREAT:如果信号量不存在,则创建它。
    • O_EXCL:与 O_CREAT 一起使用,确保如果信号量已存在,不再创建。
  • mode:指定信号量的权限。
  • value:指定信号量的计数器初始值。

返回值

  • 如果函数执行成功,返回指向信号量的指针,有名字的信号量以文件形式被创建在 /dev/shm 目录下。
  • 如果函数执行失败,返回 SEM_FAILED。

二值信号量与计数信号量

根据参数 value 指定的值,可以将信号量分为二值信号量和计数信号量。

  • 二值信号量:信号量的值只有 0 和 1,若资源不可用,信号量的值为0,若资源可用,则信号量的值为1。
  • 计数信号量:信号量的值在0到一个大于1的限制值(POSIX指出系统的最大限制值至少要为32767)。该计数表示可用资源的个数。

关闭信号量

sem_close() 函数用于关闭一个已经打开的有名信号量,该函数定义如下:

#include <semaphore.h>

int sem_close(sem_t *sem);

参数说明

  • sem:指向已打开有名信号量的指针。

返回值

  • 如果函数执行成功,返回 0。
  • 如果发生错误,返回 -1。可以通过 errno 变量来获取具体的错误信息。

删除信号量文件

sem_unlink() 函数用于删除有名信号量资源,调用此函数后,会删除 /dev/shm 目录下的文件,其他进程无法再通过该名称来访问或打开这个信号量。该函数定义如下:

#include <semaphore.h>

int sem_unlink(const char *name);

参数说明

  • sem:指定要删除的有名信号量的名称。

返回值

  • 如果函数执行成功,返回 0。
  • 如果发生错误,返回 -1。可以通过 errno 变量来获取具体的错误信息。

等待信号量

等待信号量的函数有两个 sem_wait() 函数和 sem_trywait() 函数。通过检查信号量的值,如果当前值小于或等于0,则调用进程阻塞,直到该值变成大于0。如果当前值大于0,解除阻塞后将信号量值减一,进程访问临界区资源。

sem_wait() 函数定义如下:

#include <semaphore.h>

int sem_wait(sem_t *sem);

参数说明

  • sem:指向要等待的信号量的指针。

返回值

  • 如果成功执行P操作,则函数返回0。
  • 如果发生错误,返回 -1。可以通过 errno 变量来获取具体的错误信息。

sem_trywait() 函数定义如下:

int sem_trywait(sem_t *sem);

参数说明

  • sem:指向要等待的信号量的指针。

返回值

  • 如果成功执行P操作,则函数返回0。
  • 如果信号量的值为0,表示无法立即执行 P 操作,返回 -1 并设置 errno 为 EAGAIN。
  • 如果发生其他错误,返回 -1。

释放信号量

sem_post() 函数将信号量的值加1,如果有进程阻塞着等待该信号量,那么其中一个进程将被唤醒。该函数定义如下:

#include <semaphore.h>

int sem_post(sem_t *sem);

参数说明

  • sem:指向要释放的信号量的指针。

返回值

  • 如果函数执行成功,返回 0。
  • 如果发生错误,返回 -1。可以通过 errno 变量来获取具体的错误信息。

无名信号量

无名信号量不会在文件系统中创建创建 IPC 名字,因此仅限于创建该信号量的进程中使用,用于多线程间的同步和互斥。不同进程之间的无名信号量是不能直接访问的。

无名信号量的使用流程:

  1. 使用 sem_init() 函数来创建无名信号量。
  2. 使用无名信号量,通过sem_wait() 函数来获取信号量,并执行相应的操作。当线程完成所需操作后,可以使用 sem_post() 函数释放信号量。
  3. 销毁无名信号量:在不再需要无名信号量时,可以使用 sem_destroy() 函数来删除信号量,并释放相关的系统资源。

创建无名信号量-sem_init() 函数

sem_init() 函数用于初始化无名信号量,该函数定义如下:

#include <semaphore.h>

int sem_init(sem_t *sem, int pshared, unsigned int value);

参数说明

  • sem:指向需要初始化的信号量的指针。初始化成功后,该指针将指向一个有效的信号量对象。
  • pshared:指定是否将信号量用于多个进程间的共享。取值如下:
    • 0:该信号量仅在当前进程中有效。
    • 非0:信号量可在不同进程间共享。在多个进程间共享信号量时,需要保证它们有同一个 sem 地址,通常使用共享内存来实现。
  • value:指定信号量的初始值。

返回值

  • 如果函数执行成功,返回 0。
  • 如果发生错误,返回 -1。可以通过 errno 变量来获取具体的错误信息。

销毁信号量-sem_destroy() 函数

sem_destroy() 函数用于销毁无名信号量,释放信号量占用的系统资源。该函数定义如下:

#include <semaphore.h>

int sem_destroy(sem_t *sem);

参数说明

sem:指向需要销毁的信号量的指针。

返回值

  • 如果函数执行成功,返回 0。
  • 如果发生错误,返回 -1。可以通过 errno 变量来获取具体的错误信息。

在销毁信号量之前,应该确保该信号量不再被使用,所有线程都已经释放资源。一旦信号量被销毁,其行为将变得不可预测。

进程间通信-POSIX 信号量的更多相关文章

  1. 进程间通信--POSIX信号量

    1.未决和阻塞标志可以用相同的数据类型sigset_t来存储,sigset_t称为信号集,这个类型可以表示每个信号的“有效”或“无效”状态,在阻塞信号集中“有效”和“无效”的含义是该信号是否被阻塞,而 ...

  2. Linux进程间通信IPC学习笔记之同步二(Posix 信号量)

    Linux进程间通信IPC学习笔记之同步二(Posix 信号量)

  3. 进程间通信之POSIX信号量

    POSIX信号量接口,意在解决XSI信号量接口的几个不足之处: POSIX信号量接口相比于XSI信号量接口,允许更高性能的实现. POSIX信号量接口简单易用:没有信号量集,其中一些接口模仿了我们熟悉 ...

  4. Linux进程同步之POSIX信号量

    POSIX信号量是属于POSIX标准系统接口定义的实时扩展部分.在SUS(Single UNIX Specification)单一规范中,定义的XSI IPC中也同样定义了人们通常称为System V ...

  5. linux内核剖析(十)进程间通信之-信号量semaphore

    信号量 什么是信号量 信号量的使用主要是用来保护共享资源,使得资源在一个时刻只有一个进程(线程)所拥有. 信号量的值为正的时候,说明它空闲.所测试的线程可以锁定而使用它.若为0,说明它被占用,测试的线 ...

  6. system V信号量和Posix信号量

    一.函数上的区别 信号量有两种实现:传统的System V信号量和新的POSIX信号量.它们所提供的函数很容易被区分:对于所有System V信号量函数,在它们的名字里面没有下划线.例如,应该是sem ...

  7. Linux进程间通信之信号量

    春节过去了,真的过去一年了.在公司待了快一年了.2016希望自己变得越来越好. ps:上面那句话是年前写的,中间隔了那么久,自己也变懒了. 一.信号量 1,信号量本质是一个计数器,控制访问共享资源的最 ...

  8. 第10章 Posix 信号量

    10.1 概述 10.1.1 信号量类型 Posix有名信号量:使用Posix IPC名字,可用于进程或线程间同步: Posix基于内存的信号量:也叫做无名信号量,存放在共享内存中,可用于进程或线程间 ...

  9. Linux多线程实践(5) --Posix信号量与互斥量解决生产者消费者问题

    Posix信号量 Posix 信号量 有名信号量 无名信号量 sem_open sem_init sem_close sem_destroy sem_unlink sem_wait sem_post ...

  10. POSIX信号量

    DESCRIPTION POSIX 信号量允许进程间和线程间同步他们的操作. 一个信号量是一个整型(integer),其值不能小于0. 信号量允许2中操作:给信号量的值加1(sem_post); 给信 ...

随机推荐

  1. Oracle DBA末日or重生?不会APEX=淘汰!

    残酷现实:传统DBA正在消失 "只会调优SQL的DBA,正在沦为数据库修理工!" 掌握APEX的DBA,薪资翻3倍,秒变企业核心资产! 一.DBA的死刑通知书 1. 云+AI:直接 ...

  2. docker - [03] docker原理

    题记 一.docker是怎么工作的 docker是一个CS(Client - Server)结构的系统,docker的守护进程运行在主机上,通过Socket从客户端访问. docker Server接 ...

  3. Flink学习(十七) Emitting to Side Outputs(侧输出)

    我们在生产实践中经常会遇到这样的场景,需把输入源按照需要进行拆分,比如我期望把订单流按照金额大小进行拆分,或者把用户访问日志按照访问者的地理位置进行拆分等.面对这样的需求该如何操作呢? 大部分的Dat ...

  4. php服务器如何验证令牌

    在PHP中,令牌通常用于防止跨站请求伪造(CSRF)攻击.以下是一个简单的例子,展示了如何生成和验证令牌: 生成令牌: function generateToken($length = 32) { / ...

  5. 稳定且高性价比的大模型存储:携程 10PB 级 JuiceFS 工程实践

    在过去两年多的时间里,随着 AI 大模型的快速发展,JuiceFS 在携程内部得到了越来越多 AI 用户的关注.目前,携程通过 JuiceFS 管理着 10PB 数据规模,为 AI 训练等多个场景提供 ...

  6. WordPress域名更换小记

    WordPress域名更换记录 1.准备工作 ​ 在开始之前,要有一个全面的备份,包括网站的文件和数据库.这确保了如果出现问题,你可以恢复到更改之前的状态.不然中间卡壳直接连后台都打不开了,只能重装. ...

  7. webpack 科学修改 node_modules 某个包的部分文件为本地文件

    需求总是千变万化,npm 不是万能的,node_modules 里面的文件也是需要维护的. 如果 npm install 安装了某个包,然而这个包里面部分文件不支持你的需求,这时候怎么办? 比如:ht ...

  8. [tldr]通过指令获取github仓库的单个文件的内容

    针对一个公开的github仓库,有些时候不需要clone整个仓库的内容,只需要对应的几个文件.但是直接通过网页点击下载文件很麻烦,在服务器上也不好这样操作. 因此,如何使用curl或者wget指令快速 ...

  9. selenium自动化测试+OCR-获取图片页面小说

    随着爬虫技术的发展,反爬虫技术也越来越高. 目前有些网站通过自定义字体库的方式实现反爬,主要表现在页面数据显示正常,但是页面获取到的实际数据是别的字符或者是一个编码.这种反爬需要解析网站自己的字体库, ...

  10. 编写你的第一个 Django 应用程序,第7部分

    本教程从教程 6 停止的地方开始.我们将继续使用网络投票应用程序,并将专注于自定义 Django 自动生成的管理站点,这是我们在教程 2 中首次探索的. 一.自定义管理表单 通过用 admin.sit ...