当前位置: 首页 > news >正文

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_进程间通信_信号灯

概述 什么是信号灯&#xff1a; 信号灯也称为信号量&#xff0c;代表的是一类资源&#xff0c;其值表示系统中该资源的数量。 主要用途是实现进程、线程的同步。 什么是P/V操作&#xff1a; P操作就是申请资源&#xff0c;V操作就是释放操作。 信号灯的种类&#xff1a; …...

Linux——cp-mv-rm命令

cp命令 复制文件 cp test01.txt test02.txt 复制文件夹 cp -r hsy01 hsy02 mv命令 移动文件/文件夹 rm命令 删除文件 rm test.txt 删除文件夹&#xff08;目录 rm -r hsy01 通配符 * 匹配任意内容 注意* 位置 强制删除-f root超级管理员...

上升点列

题目描述 在一个二维平面内&#xff0c;给定 n 个整数点 (xi​,yi​)&#xff0c;此外你还可以自由添加 k 个整数点。 你在自由添加 k 个点后&#xff0c;还需要从 nk 个点中选出若干个整数点并组成一个序列&#xff0c;使得序列中任意相邻两点间的欧几里得距离恰好为 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商城首页小程序-代码生成器

在设计一个小程序的首页时&#xff0c;包含轮播图、通知栏和商品列表这三个元素是非常常见且有效的布局方式。这样的设计既能够吸引用户的注意力&#xff0c;又能够高效地展示信息和商品。 轮播组件 小程序首页幻灯片通常位于小程序的顶部或显著位置&#xff0c;通过滑动屏幕可…...

Vue3 富文本:WangEditor

wangEditor 开源 Web 富文本编辑器&#xff0c;开箱即用&#xff0c;配置简单 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&#xff08;k8s&#xff09;中最小的资源管理组件&#xff0c;也是最小化运行容器化应用的资源对象。以下是对Pod的详细介绍&#xff1a; 一、Pod的基本概念 定义&#xff1a;Pod是Kubernetes中可以创建和管理的最小单元&#xff0c;是资源对象模型中由用户创…...

软件测试面试题大全

什么是软件测试&#xff1f; 答案&#xff1a;软件测试是一系列活动&#xff0c;旨在评估软件产品的质量&#xff0c;并验证它是否满足规定的需求。它包括执行程序或系统以识别任何缺陷、问题或错误&#xff0c;并确保软件产品符合用户期望。 软件测试的目的是什么&#xff1f…...

SQL第16课挑战题

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

Python3 爬虫 中间人爬虫

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

Leetcode 50. Pow ( x , n ) 快速幂、取模 C++实现

问题&#xff1a;Leetcode 50. Pow ( x , n ) 实现 pow(x, n) &#xff0c;即计算 x 的整数 n 次幂函数。 算法&#xff1a; 具体实现流程如下&#xff1a; 代码&#xff1a; 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&#xff08;Java Platform&#xff0c;Standard Edition&#xff09;: Java 平台标准版&#xff0c;Java 编程语言的基础&#xff0c;它包含了支持 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 注释&#xff1a; priority1 #数字越小代表优先级越高&#xff…...

做一个不断更新的链接库

做一个不断更新的链接库 anaconda anaconda官方镜像源 anaconda清华镜像源 社区 CSDN CSDN-华为开发者空间 python开发库 股票爬虫 - akshare...

Ping32企业加密软件:保护数据安全

在数字化时代&#xff0c;数据安全已成为每个企业不可忽视的重要课题。无论是客户信息、财务报表&#xff0c;还是商业机密&#xff0c;数据的安全性直接关系到企业的声誉与运营。为了应对不断变化的安全威胁&#xff0c;选择一款可靠的企业加密软件尤为重要。在这里&#xff0…...

【Java】异常的处理-方式【主线学习笔记】

文章目录 前言1、处理概述2、Java异常处理机制&#xff08;方式&#xff09;方式一&#xff08;抓抛模型&#xff09;&#xff1a;try-catch-finally方式二&#xff1a;throws 异常类型总结 前言 Java是一门功能强大且广泛应用的编程语言&#xff0c;具有跨平台性和高效的执行…...

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+花生壳实现远程访问

有远程办公的需求&#xff0c;以及一些其他东西。 为什么写&#xff1f; ax1500路由器好像没搜到相关信息。以及其中有一点坑。 前置 公网ip Xiaomi路由器 AX1500 MiWiFi 稳定版 1.0.54 实现流程 花生壳申请壳域名https://console.hsk.oray.com/ 这里需要为域名实名认证 …...

相机从app启动流程

一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...

C++.OpenGL (10/64)基础光照(Basic Lighting)

基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...

MySQL用户和授权

开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务&#xff1a; test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...

OPENCV形态学基础之二腐蚀

一.腐蚀的原理 (图1) 数学表达式&#xff1a;dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一&#xff0c;腐蚀跟膨胀属于反向操作&#xff0c;膨胀是把图像图像变大&#xff0c;而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...

基于Java+MySQL实现(GUI)客户管理系统

客户资料管理系统的设计与实现 第一章 需求分析 1.1 需求总体介绍 本项目为了方便维护客户信息为了方便维护客户信息&#xff0c;对客户进行统一管理&#xff0c;可以把所有客户信息录入系统&#xff0c;进行维护和统计功能。可通过文件的方式保存相关录入数据&#xff0c;对…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

七、数据库的完整性

七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...

C#中的CLR属性、依赖属性与附加属性

CLR属性的主要特征 封装性&#xff1a; 隐藏字段的实现细节 提供对字段的受控访问 访问控制&#xff1a; 可单独设置get/set访问器的可见性 可创建只读或只写属性 计算属性&#xff1a; 可以在getter中执行计算逻辑 不需要直接对应一个字段 验证逻辑&#xff1a; 可以…...

STM32---外部32.768K晶振(LSE)无法起振问题

晶振是否起振主要就检查两个1、晶振与MCU是否兼容&#xff1b;2、晶振的负载电容是否匹配 目录 一、判断晶振与MCU是否兼容 二、判断负载电容是否匹配 1. 晶振负载电容&#xff08;CL&#xff09;与匹配电容&#xff08;CL1、CL2&#xff09;的关系 2. 如何选择 CL1 和 CL…...

深入理解Optional:处理空指针异常

1. 使用Optional处理可能为空的集合 在Java开发中&#xff0c;集合判空是一个常见但容易出错的场景。传统方式虽然可行&#xff0c;但存在一些潜在问题&#xff1a; // 传统判空方式 if (!CollectionUtils.isEmpty(userInfoList)) {for (UserInfo userInfo : userInfoList) {…...