12.5 Linux_进程间通信_信号灯
概述
什么是信号灯:
信号灯也称为信号量,代表的是一类资源,其值表示系统中该资源的数量。
主要用途是实现进程、线程的同步。
什么是P/V操作:
P操作就是申请资源,V操作就是释放操作。
信号灯的种类:
Posix 有名信号灯:编译时需链接pthread库。有名信号灯文件存放在/dev/shm目录下
Posix 无名信号灯:只支持线程同步,编译时需链接pthread库
System V 信号灯
Posix 信号灯
Posix 信号灯的打开/关闭/删除函数有所不同,但PV操作是使用的同一组函数。具体函数如下
1、 打开/关闭/删除
1.1 有名信号灯
//打开
sem_t *sem_open(const char *name,int oflag);
sem_t *sem_open(const char *name,int oflag,mode_t mode,unsigned int value);
//关闭
int sem_close(sem_t *sem);
//删除
int sem_unlink(const char *name);
返回值:成功返回信号量指针,失败返回SEM_FAILED
name:信号灯的名字,即:文件名
oflag:打开方式,常用O_CREAT
mode:文件权限,常用0666
value:信号量值。二元信号灯值为1,普通信号灯表示资源数目。
1.2 无名信号灯
//创建
int sem_init(sem_t *sem, int pshared, unsigned int value);
//销毁
int sem_destroy(sem_t *sem);
sem:信号量指针
pshared:写0,代表不能在进程间共享。Linux中无名信号灯不能在进程间通信
value:信号量值。
2、P/V操作
2.1 P操作
int sem_wait(sem_t *sem);
当信号量为0时,进入阻塞,直到信号量不为0
当信号量不为0时,会将信号量的值-1
2.2 V操作
int sem_post(sem_t *sem);
该函数使用后会将信号量值+1
System V 信号灯
1、创建
int semget(key_t key, int nsems, int semflg);
返回值:成功返回信号灯id,失败返回-1
key:键值,由ftok生成
nsems:信号灯的个数
semflg:权限,通常写为IPC_CREAT|0666
2、控制信号灯
int semctl(int semid, int semnum, int cmd, ...);
semid:信号灯id
semnum:操作哪一个信号灯,序号从0开始
cmd:写入IPC_RMID,代表删除操作
写入SETVAL,代表初始化信号灯的值,此时需要传入第四个参数,类型是共用体
union semun共用体:
union semun {int val; //设置信号灯的初始值struct semid_ds *buf;unsigned short *array;
} arg;
3、P/V操作
int semop(int semid, struct sembuf *sops, size_t nsops);
semid:信号灯id
sops:P/V操作
nsops:要操作的信号灯个数,通常写1
struct sembuf结构体:
struct sembuf {unsigned short sem_num; //要操作的信号灯的编号short sem_op; //1:V操作,-1:P操作short sem_flg; //0:阻塞,IPC_NOWAIT不阻塞
};
示例代码
1、有名信号灯
见博文"12.2 Linux_进程间通信_共享内存"-"相关函数"-"实验代码"-"2、AB进程互传数据"
博文链接为:12.2 Linux_进程间通信_共享内存-CSDN博客
2、无名信号灯
无名信号灯只能用于线程间通信,下面是无名信号灯实现AB线程利用共享内存互传数据。
#include <stdio.h>
#include <errno.h>
#include <pthread.h>
#include <sys/mman.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <semaphore.h>sem_t sem_mmap;
void* mmap_addr = NULL;
char buf[100] = {0};
int i=0;
void* Afun(void* arg){memcpy(mmap_addr,"A Start SIG",strlen("A Start SIG"));while(1){sem_wait(&sem_mmap);if(*(char*)mmap_addr == 'B'){//读出B线程写入的内容printf("A read:%s\n",(char*)mmap_addr+strlen("B"));//读取数据,不读取数据来源标号memset(mmap_addr,0,strlen(mmap_addr));//清空缓冲区//写入新数据memcpy(mmap_addr,"A",strlen("A"));//数据来源标号sprintf(buf,"A_Data:%d",i++); //新数据memcpy(mmap_addr+strlen("A"),buf,strlen(buf));}sem_post(&sem_mmap);}
}
void* Bfun(void* arg){while(1){sem_wait(&sem_mmap);if(*(char*)mmap_addr == 'A'){//读出A线程写入的内容printf("B read:%s\n",(char*)mmap_addr+strlen("A"));memset(mmap_addr,0,strlen(mmap_addr));//清空缓冲区//写入新数据memcpy(mmap_addr,"B",strlen("B"));//数据来源标号sprintf(buf,"B get A data,B data is %d",i++); //新数据memcpy(mmap_addr+strlen("B"),buf,strlen(buf));sleep(1);}sem_post(&sem_mmap);}
}#define FILE_PATH "./mmap"
int main(){pthread_t tid[2];int fd;//打开文件if((fd=open(FILE_PATH,O_RDWR)) < 0){perror("open");return -1;}//创建共享内存映射if((mmap_addr = mmap(NULL,4*1024,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0)) == MAP_FAILED){perror("mmap");return -1;}memset(mmap_addr,lseek(fd,0,SEEK_END),strlen(mmap_addr));//清空缓冲区close(fd);//创建共享内存映射后可以关闭文件描述符//创建信号量sem_init(&sem_mmap,0,1);//创建线程pthread_create(&tid[0],NULL,Afun,NULL);pthread_create(&tid[1],NULL,Bfun,NULL);while(1);return 0;
}
3、System V信号灯
使用SystemV信号灯实现"有名信号灯"章节的同样功能
A.c代码如下:
#include <sys/sem.h>
#include <sys/mman.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>#define FILE_PATH "./mmap"
union semun {int val; //设置信号灯的初始值struct semid_ds *buf;unsigned short *array;
} arg;
int main(){int fd;void* mmap_addr = NULL;int i=0;char buf[100] = {0};key_t key;int sem_mmap;struct sembuf semPV;//打开文件if((fd=open(FILE_PATH,O_RDWR)) < 0){perror("open");return -1;}//创建共享内存映射if((mmap_addr = mmap(NULL,4*1024,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0)) == MAP_FAILED){perror("mmap");return -1;}memset(mmap_addr,0,lseek(fd,0,SEEK_END));//清空缓冲区close(fd);//创建共享内存映射后可以关闭文件描述符//创建信号量key = ftok(".",1);if((sem_mmap = semget(key,1,IPC_CREAT|0666)) == -1){perror("sem_get");return -1;}arg.val = 1;semctl(sem_mmap,0,SETVAL,arg);//进程间通信memcpy(mmap_addr,"A Start SIG",strlen("A Start SIG"));while(1){semPV.sem_num = 0;semPV.sem_op=-1;semPV.sem_flg=0;semop(sem_mmap,&semPV,1);if(*(char*)mmap_addr == 'B'){//读出B进程写入的内容printf("A read:%s\n",(char*)mmap_addr+strlen("B"));//读取数据,不读取数据来源标号memset(mmap_addr,0,strlen(mmap_addr));//清空缓冲区//写入新数据memcpy(mmap_addr,"A",strlen("A"));//数据来源标号sprintf(buf,"A_Data:%d",i++); //新数据memcpy(mmap_addr+strlen("A"),buf,strlen(buf));}semPV.sem_num = 0;semPV.sem_op=1;semPV.sem_flg=0;semop(sem_mmap,&semPV,1);}return 0;
}
B.c的代码如下:
#include <sys/mman.h>
#include <sys/sem.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>#define FILE_PATH "./mmap"
union semun {int val; //设置信号灯的初始值struct semid_ds *buf;unsigned short *array;
} arg;
int main(){int fd;void* mmap_addr = NULL;int i=0;char buf[100] = {0};key_t key;int sem_mmap;struct sembuf semPV;//打开文件if((fd=open(FILE_PATH,O_RDWR)) < 0){perror("open");return -1;}//创建共享内存映射if((mmap_addr = mmap(NULL,4*1024,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0)) == MAP_FAILED){perror("mmap");return -1;}memset(mmap_addr,0,lseek(fd,0,SEEK_END));//清空缓冲区close(fd);//创建共享内存映射后可以关闭文件描述符//创建信号量key = ftok(".",1);if((sem_mmap = semget(key,1,IPC_CREAT|0666)) == -1){perror("sem_get");return -1;}arg.val = 1;semctl(sem_mmap,0,SETVAL,arg);//进程间通信while(1){semPV.sem_num = 0;semPV.sem_op=-1;semPV.sem_flg=0;semop(sem_mmap,&semPV,1);if(*(char*)mmap_addr == 'A'){//读出A进程写入的内容printf("B read:%s\n",(char*)mmap_addr+strlen("A"));memset(mmap_addr,0,strlen(mmap_addr));//清空缓冲区//写入新数据memcpy(mmap_addr,"B",strlen("B"));//数据来源标号sprintf(buf,"B get A data,B data is %d",i++); //新数据memcpy(mmap_addr+strlen("B"),buf,strlen(buf));sleep(1);}semPV.sem_num = 0;semPV.sem_op=1;semPV.sem_flg=0;semop(sem_mmap,&semPV,1);}return 0;
}
相关文章:
12.5 Linux_进程间通信_信号灯
概述 什么是信号灯: 信号灯也称为信号量,代表的是一类资源,其值表示系统中该资源的数量。 主要用途是实现进程、线程的同步。 什么是P/V操作: P操作就是申请资源,V操作就是释放操作。 信号灯的种类: …...

Linux——cp-mv-rm命令
cp命令 复制文件 cp test01.txt test02.txt 复制文件夹 cp -r hsy01 hsy02 mv命令 移动文件/文件夹 rm命令 删除文件 rm test.txt 删除文件夹(目录 rm -r hsy01 通配符 * 匹配任意内容 注意* 位置 强制删除-f root超级管理员...
上升点列
题目描述 在一个二维平面内,给定 n 个整数点 (xi,yi),此外你还可以自由添加 k 个整数点。 你在自由添加 k 个点后,还需要从 nk 个点中选出若干个整数点并组成一个序列,使得序列中任意相邻两点间的欧几里得距离恰好为 1 而且…...

刷题 链表
面试经典150题 - 链表 141. 环形链表 class Solution { public:bool hasCycle(ListNode *head) {ListNode* slow head, *fast head;while (fast ! nullptr && fast->next ! nullptr) {slow slow->next;fast fast->next->next;if (slow fast) {return…...
SQL 语法学习指南
目录 前言1. SQL 的基本概念1.1 SQL 的作用1.2 SQL 的特点 2. SQL 的基础语法2.1 数据查询 - SELECT 语句2.2 数据插入 - INSERT 语句2.3 数据更新 - UPDATE 语句2.4 数据删除 - DELETE 语句 3. SQL 的进阶语法3.1 聚合函数3.2 表连接 - JOIN3.3 子查询 4. SQL 学习建议4.1 多实…...

低代码可视化-uniapp商城首页小程序-代码生成器
在设计一个小程序的首页时,包含轮播图、通知栏和商品列表这三个元素是非常常见且有效的布局方式。这样的设计既能够吸引用户的注意力,又能够高效地展示信息和商品。 轮播组件 小程序首页幻灯片通常位于小程序的顶部或显著位置,通过滑动屏幕可…...
Vue3 富文本:WangEditor
wangEditor 开源 Web 富文本编辑器,开箱即用,配置简单 wangEditor 1. 安装依赖包 npm install wangeditor/editor-for-vuenext --save 2. 在引用页面加入如下代码 <template><div style"border: 1px solid #ccc"><Toolbar …...

Unity实现自定义图集(四)
以下内容是根据Unity 2020.1.0f1版本进行编写的 在之前的篇章中已经把自定义图集在编辑器上的使用,以及运行时所需的信息都准备好了,接下来就是魔改UGUI的Image组件,使其能够像Image那样运行时如果引用的资源有打自定义图集,则加载对应自定义图集的Texture。 1、思路 …...

k8s-pod的管理及优化设置
Pod是Kubernetes(k8s)中最小的资源管理组件,也是最小化运行容器化应用的资源对象。以下是对Pod的详细介绍: 一、Pod的基本概念 定义:Pod是Kubernetes中可以创建和管理的最小单元,是资源对象模型中由用户创…...
软件测试面试题大全
什么是软件测试? 答案:软件测试是一系列活动,旨在评估软件产品的质量,并验证它是否满足规定的需求。它包括执行程序或系统以识别任何缺陷、问题或错误,并确保软件产品符合用户期望。 软件测试的目的是什么?…...

SQL第16课挑战题
1. 美国各州的缩写应始终用大写。更新所有美国地址,包括供应商状态(Vendors表中的vend_state)和顾客状态(customers表中的cust_state),使它们均为大写。 2. 第15课挑战题1要求将自己添加到customers表中,现在删除自己,…...

Python3 爬虫 中间人爬虫
中间人(Man-in-the-Middle,MITM)攻击是指攻击者与通信的两端分别创建独立的联系,并交换其所收到的数据,使通信的两端认为其正在通过一个私密的连接与对方直接对话,但事实上整个会话都被攻击者完全控制。在中…...

Leetcode 50. Pow ( x , n ) 快速幂、取模 C++实现
问题:Leetcode 50. Pow ( x , n ) 实现 pow(x, n) ,即计算 x 的整数 n 次幂函数。 算法: 具体实现流程如下: 代码: class Solution { public:double myPow(double x, int N) {double ans 1;long long n N;if (n <…...

Java SE vs Java EE 与 JVM vs JDK vs JRE
Java SE(Java Platform,Standard Edition): Java 平台标准版,Java 编程语言的基础,它包含了支持 Java 应用程序开发和运行的核心类库以及虚拟机等核心组件。Java SE 可以用于构建桌面应用程序或简单的服务器应用程序。…...

Linux YUM设置仓库优先级
1.安装yum-plugin-priorities优先级插件 yum install yum-plugin-priorities -y 2.设置仓库优先级 vim /etc/yum.repos.d/local.repo [local] namecentos7.5 baseurlfile:///mnt enable1 gpgcheck0 priority1 注释: priority1 #数字越小代表优先级越高ÿ…...
做一个不断更新的链接库
做一个不断更新的链接库 anaconda anaconda官方镜像源 anaconda清华镜像源 社区 CSDN CSDN-华为开发者空间 python开发库 股票爬虫 - akshare...

Ping32企业加密软件:保护数据安全
在数字化时代,数据安全已成为每个企业不可忽视的重要课题。无论是客户信息、财务报表,还是商业机密,数据的安全性直接关系到企业的声誉与运营。为了应对不断变化的安全威胁,选择一款可靠的企业加密软件尤为重要。在这里࿰…...
【Java】异常的处理-方式【主线学习笔记】
文章目录 前言1、处理概述2、Java异常处理机制(方式)方式一(抓抛模型):try-catch-finally方式二:throws 异常类型总结 前言 Java是一门功能强大且广泛应用的编程语言,具有跨平台性和高效的执行…...
React modal暴露ref简洁使用
父组件使用 import { useRef } from react import { FormModal } from ./modalconst IndexRoute () > {const formRef useRef<any>()const openModal (row?: any) > {const params {title: row?.id ? 【${row.name}】编辑 : 创建,isView: false,row,api: r…...

小米路由器ax1500+DDNS+公网IP+花生壳实现远程访问
有远程办公的需求,以及一些其他东西。 为什么写? ax1500路由器好像没搜到相关信息。以及其中有一点坑。 前置 公网ip Xiaomi路由器 AX1500 MiWiFi 稳定版 1.0.54 实现流程 花生壳申请壳域名https://console.hsk.oray.com/ 这里需要为域名实名认证 …...
基于算法竞赛的c++编程(28)结构体的进阶应用
结构体的嵌套与复杂数据组织 在C中,结构体可以嵌套使用,形成更复杂的数据结构。例如,可以通过嵌套结构体描述多层级数据关系: struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...

使用分级同态加密防御梯度泄漏
抽象 联邦学习 (FL) 支持跨分布式客户端进行协作模型训练,而无需共享原始数据,这使其成为在互联和自动驾驶汽车 (CAV) 等领域保护隐私的机器学习的一种很有前途的方法。然而,最近的研究表明&…...

高频面试之3Zookeeper
高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个?3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制(过半机制࿰…...

SpringTask-03.入门案例
一.入门案例 启动类: package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...
【Go语言基础【13】】函数、闭包、方法
文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数(函数作为参数、返回值) 三、匿名函数与闭包1. 匿名函数(Lambda函…...
AGain DB和倍数增益的关系
我在设置一款索尼CMOS芯片时,Again增益0db变化为6DB,画面的变化只有2倍DN的增益,比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析: 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...
C#学习第29天:表达式树(Expression Trees)
目录 什么是表达式树? 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持: 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...
掌握 HTTP 请求:理解 cURL GET 语法
cURL 是一个强大的命令行工具,用于发送 HTTP 请求和与 Web 服务器交互。在 Web 开发和测试中,cURL 经常用于发送 GET 请求来获取服务器资源。本文将详细介绍 cURL GET 请求的语法和使用方法。 一、cURL 基本概念 cURL 是 "Client URL" 的缩写…...

一些实用的chrome扩展0x01
简介 浏览器扩展程序有助于自动化任务、查找隐藏的漏洞、隐藏自身痕迹。以下列出了一些必备扩展程序,无论是测试应用程序、搜寻漏洞还是收集情报,它们都能提升工作流程。 FoxyProxy 代理管理工具,此扩展简化了使用代理(如 Burp…...

数据分析六部曲?
引言 上一章我们说到了数据分析六部曲,何谓六部曲呢? 其实啊,数据分析没那么难,只要掌握了下面这六个步骤,也就是数据分析六部曲,就算你是个啥都不懂的小白,也能慢慢上手做数据分析啦。 第一…...