Linux多进程通信(2)——POSIX信号量使用例程

news2024/11/25 4:38:29

1.POSIX信号量

1)POSIX信号量和System V信号量区别
常用的是POSIX信号量,使用起来更加方便,而POSIX信号量分为有名信号量和无名信号量

POSIX信号量是多线程多进程安全的,而System V标准的信号量并不是,Posix通过sem_open单一的调用就完成了信号量的创建、初始化和权限的设置,而System V要两步。

POSIX无名信号量,非多进程共享时,相当于存放在进程的全局变量,进程结束则内存销毁,而若是有名信号量,则存在共享内存中,只要共享内存区存在,则信号灯就一直存在,这也是使用时经常发现sem_open调用失败的原因

POSIX信号量,用ls /dev/shm能看到,而System V信号量,则是使用ipcs -s查看。

2)无名信号量和有名信号量
有名信号量:可以在多进程间使用,多进程通过名字来打开同一个信号量,使用范围更广
无名信号量:一般在多线程使用,因为没有名字,所以没法在多进程中打开同一个信号量
image.png

2.信号量创建

1)有名信号量

#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>
sem_t *sem_open(const char *name, int oflag);
sem_t *sem_open(const char *name, int oflag,mode_t mode, unsigned int value);

oflag:可取O_CREAT和O_EXCL,取O_CREAT时,表示要创建信号量,用O_CREAT时文件存在,就返回错误信息,一般会使用O_CREAT和O_EXCL一起,信号量不存在则创建,存在则报错
mode:读写权限,如0777
value:信号量初始值

2)无名信号量

#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);

sem:信号量指针
pshared:0,用于线程间(全局变量),非0用于进程间(共享内存)
value:信号量初始值

3.信号量销毁

1)有名信号量

#include <semaphore.h>
int sem_close(sem_t *sem); /// 信号量关闭
int sem_unlink(const char *name); ///信号量删除

信号量关闭并不等于删除。
进程会记录进程和信号的关系,调用sem_close时,会终止这种关联关系,信号量的进程数的引用计数减1,但即使通过调用sem_close将信号量计数到0,也不会删除
而调用sem_unlink时,若引用计数不为0,则需要当所有打开该信号量的进程,都将信号量关闭,才会真正进行删除操作

2)无名信号量

#include <semaphore.h>
int sem_destroy(sem_t *sem);

调用sem_destroy时,只有当所有进程都不再等待这个信号量时需要用户确保!),才能安全销毁。

4.等待信号量

#include <semaphore.h>
int sem_wait(sem_t *sem);
int sem_trywait(sem_t *sem);
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);

若信号量计数大于0,则成功拿到信号量,信号量计数-1,可以访问共享资源,若信号量计数小于等于0,则无法拿到信号量,执行的进程会放到PCB等待队列
sem_wait:阻塞等待信号量,拿到信号量再返回
sem_trywait:非阻塞尝试拿信号量,不阻塞。成功则返回0,失败返回EAGAIN
sem_timedwait:设定最大超时的阻塞式等待信号量,若不超时返回0,超过abs_timeout的等待时间,则返回-1, 并置errno为ETIMEOUT。

使用sem_timedwait的陷阱:

4.发布信号量

#include <semaphore.h>
int sem_post(sem_t *sem);

表示共享资源使用完毕,归还共享资源,使信号量计数+1
如果发布信号量之前, 信号量的值是0, 并且已经有进程或线程正等待在信号量上, 此时会有一个进程被唤醒, 被唤醒的进程会继续sem_wait函数的减1操作。如果有多个进程正等待在信号量上, 那么将无法确认哪个进程会被唤醒。如果发布信号量时,并没有进程在等待,则内核会维护这个计数,直到有人来取走信号量。
函数调用成功时, 返回0; 失败时, 返回-1, 并置errno。 当参数sem并不指向合法的信号量时, 置errno为EINVAL; 当信号量的值超过上限时, 置errno为EOVERFLOW

5.例程

1)server.c

#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>
#include <stdio.h>

#define SEM_NAME "sem_test"
int main(int argc, char **argv)
{
    int iRet = 0;
    int iSemCnt = 0;
    sem_t *pSem = sem_open(SEM_NAME, O_CREAT|O_EXCL, 0777, 1);
    if (!pSem)
    {
        printf("server sem open failed\n");
        return -1;
    }
    sem_getvalue(pSem, &iSemCnt);
    printf("server begin for wait sem:%p, sem cnt:%d\n", pSem, iSemCnt);
    sem_wait(pSem);
    sem_getvalue(pSem, &iSemCnt);
    printf("server wait sem:%p success, sem cnt:%d\n", pSem, iSemCnt);

    sleep(5);
    sem_post(pSem);
    sem_getvalue(pSem, &iSemCnt);
    printf("server send sem:%p success, sem cnt:%d\n", pSem, iSemCnt);

    sleep(5);
    sem_close(pSem);
    sem_unlink(SEM_NAME);

    return 0;
}

2)client.c

#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>
#include <stdio.h>

#define SEM_NAME "sem_test"
int main(int argc, char **argv)
{
    int iRet = 0;
    int iSemCnt = 0;
    sem_t *pSem = sem_open(SEM_NAME, O_RDWR);
    if (!pSem)
    {
        printf("server sem open failed\n");
        return -1;
    }
    sem_getvalue(pSem, &iSemCnt);
    printf("client begin for wait sem:%p, sem cnt:%d\n", pSem, iSemCnt);
    sem_wait(pSem);
    sem_getvalue(pSem, &iSemCnt);
    printf("client wait sem:%p success, sem cnt:%d\n", pSem, iSemCnt);

    sleep(5);

    sem_close(pSem);
    printf("client close sem: success\n", pSem);

    return 0;
}

其中server在open打开信号量后,设置计数为1,并进行wait操作,之后延时5S发送信号量,这个信号量成功被client给拿到,打印等待成功。
image.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1561679.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

java----继承

1、继承的定义 继承就是子类继承父类的特征和行为&#xff0c;使得子类对象具有父类的属性和方法&#xff08;不劳而获&#xff09; 使用 extends关键字 2、方法重写&#xff08;方法覆盖&#xff09; 子类可以重写父类中的方法&#xff0c;要求方法签名必须一样 3、方法重载…

2、jvm基础知识(二)

类的生命周期 加载 1、加载(Loading)阶段第一步是类加载器根据类的全限定名通过不同的渠道以二进制流的方式获取字节码信息。 程序员可以使用Java代码拓展的不同的渠道。 2、类加载器在加载完类之后&#xff0c;Java虚拟机会将字节码中的信息保存到内存的方法区中。在方法区生…

【已解决】Port 8080 was already in use

问题描述 运行项目时显示错误页&#xff0c;无法成功进入目标页 *************************** APPLICATION FAILED TO START ***************************Description:Web server failed to start. Port 8080 was already in use.Action:Identify and stop the process thats…

MySQL常见故障案例与优化介绍

前言 MySQL故障排查的意义在于及时识别并解决数据库系统中的问题&#xff0c;确保数据的完整性和可靠性&#xff1b;而性能优化则旨在提高数据库系统的效率和响应速度&#xff0c;从而提升用户体验和系统整体性能。这两方面的工作都对于保证数据库系统稳定运行、提升业务效率和…

html基础:颜色的 5 种表示方法(最全!)

你好&#xff0c;我是云桃桃。一个希望帮助更多朋友快速入门 WEB 前端的程序媛&#xff0c;大专生&#xff0c;2年时间从1800到月入过万&#xff0c;工作5年买房。 分享成长心得。 HTML 颜色在网页设计中扮演着重要角色&#xff0c;给网页增加颜色可以增强用户体验&#xff0c;…

臻奶惠无人售货机:新零售时代的便捷消费革命

臻奶惠无人售货机&#xff1a;新零售时代的便捷消费革命 在新零售的浪潮中&#xff0c;智能无人售货机作为一个创新的消费模式&#xff0c;已经成为距离消费者最近的便捷购物点之一。这种模式不仅能够满足居民对消费升级的需求&#xff0c;还能通过建立多样化和多层次的消费体…

Spring使用(一)注解

Spring使用 资源 Spring 框架内部使用 Resource 接口作为所有资源的抽象和访问接口&#xff0c;在上一篇文章的示例代码中的配置文件是通过ClassPathResource 进行封装的&#xff0c;ClassPathResource 是 Resource 的一个特定类型的实现&#xff0c;代表的是位于 classpath …

Python创建三维空间立体方阵,根据赋予数值绘图赋色

代码如下&#xff1a; import matplotlib.pyplot as plt from mpl_toolkits.mplot3d.art3d import Poly3DCollection from matplotlib.colors import LinearSegmentedColormap, Normalize import numpy as npdef make_cube(matrix: np.ndarray)->None:fig plt.figure(figs…

vue项目视频播放ckplayer使用

ckplayer 官方网址&#xff0c;点击访问 1&#xff0c;打开网页后能看到这里&#xff0c;我现在使用的是最新 X3版手册 2&#xff0c;这个ckplayer不是npm 插件&#xff0c;要下载安装包解压到项目里面使用 安装包网址 通过gitee下载 3&#xff0c;解析安装包到项目中 publ…

leetcode 不同路径

62. 不同路径 问题描述 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为 “Finish” &#xff09;。 问总共有多少条不同的…

仿真黑科技EasyGo DeskSim 2022

DeskSim2022的FPGA支持多种solver的混合应用&#xff0c;对于每一种solver可以采用不同的仿真步长&#xff0c;以下图模型为例&#xff0c;模型运行在FPGA上&#xff0c;FPGA解算方式采用的是Power Electronic & FPGA Coder解算&#xff0c;其中电力电子电路部分采用了两种…

SD-WAN支持的多种线路类型

SD-WAN技术的崛起为企业网络带来了全新的可能性&#xff0c;尤其是在连接选项的多样性方面。通过SD-WAN方案&#xff0c;企业可以根据自身需求来选择最适合的连接类型&#xff0c;以实现性能优化和成本效益的平衡。下面&#xff0c;让我们深入了解SD-WAN所支持的各种线路类型。…

【御控物联】JavaScript JSON结构转换(12):对象To数组——键值互换属性重组

文章目录 一、JSON结构转换是什么&#xff1f;二、核心构件之转换映射三、案例之《JSON对象 To JSON数组》四、代码实现五、在线转换工具六、技术资料 一、JSON结构转换是什么&#xff1f; JSON结构转换指的是将一个JSON对象或JSON数组按照一定规则进行重组、筛选、映射或转换…

vue+elementUI实现表格组件的封装

效果图&#xff1a; 在父组件使用表格组件 <table-listref"table":stripe"true":loading"loading":set-table-h"slotProps.setMainCardBodyH":table-data"tableData":columns"columns.tableList || []":ra…

JAVAEE——多线程进阶,锁策略

文章目录 锁策略乐观锁和悲观锁乐观锁悲观锁两者的比较 读写锁重量级锁和轻量级锁重量级锁轻量级锁 自旋锁公平锁和非公平锁公平锁非公平锁 可重入锁和不可重入锁可重入锁不可重入锁 锁策略 乐观锁和悲观锁 乐观锁 什么是乐观锁呢&#xff1f;我们可以认为乐观锁比较自信&am…

MySQL 连接池的实现

池化技术 池化技术能够减少资源对象的创建次数&#xff0c;提高程序的响应性能&#xff0c;特别是在高并发下这种提高更明显。共同特征 对象创建时间长。对象创建需要大量资源。对象创建后可被重复使用。 数据库连接池 数据库连接池&#xff08;Connection pooling&#xff…

linux C:变量、运算符

linux C 文章目录 变量运算符 一、变量 [存储类型] 数据类型 标识符 值 标识符&#xff1a;由数字、字母、下划线组成的序列&#xff0c;不能以数字开头。 数据类型&#xff1a;基本数据类型构造类型 存储类型&#xff1a;auto static…

2.4_2 死锁的处理策略——预防死锁

2.4_2 死锁的处理策略——预防死锁 知识总览 #mermaid-svg-z0noPuUcH4CJsxb7 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-z0noPuUcH4CJsxb7 .error-icon{fill:#552222;}#mermaid-svg-z0noPuUcH4CJsxb7 .error-t…

【BlossomRPC】接入注册中心

文章目录 NacosZookeeper自研配置中心 RPC项目 配置中心项目 网关项目 这是BlossomRPC项目的最后一篇文章了&#xff0c;接入完毕注册中心&#xff0c;一个完整的RPC框架就设计完成了。 对于项目对注册中心的整合&#xff0c;其实我们只需要再服务启动的时候将ip/port/servic…

商城业务-检索服务

文章目录 前言一、搭建页面环境1.1 静态界面搭建1.2 Nginx 动静分离1.3 Windows 上传文件1.4 引入 thymeleaf 依赖1.5 Nginx 反向代理1.4 Nginx 配置1.5 gateway 网关配置 二、调整页面跳转2.1 引入依赖2.2 页面跳转 三、检索查询参数模型分析抽取3.1 检索业务分析3.2 检索语句…