进程间的通信3-信号量

信号量

1.资源竞争

  • 资源竞争 : 当多个进程同时访问共享资源时,会产生资源竞争,最终最导致数据混乱
  • 临界资源 : 不允许同时有多个进程访问的资源,包括硬件资源(CPU、内存、存储器以及其他外围设备)与软件资源(共享代码段、共享数据结构)
  • 临界区 : 访问临界资源代码
    在这里插入图片描述

2.同步与互斥

  • 互斥 : 同一时刻只有一个进程访问临界资源
  • 同步 : 在互斥的基础上增加了进程对临界资源的访问顺序
  • 进程主要的同步与互斥手段是信号量

3.信号量简介

信号量的起源来自于信号灯
在这里插入图片描述

  • 信号量: 由内核维护的整数,其值被限制为大于或等于0

  • 信号量可以执行如下操作:

     1.将信号量设置成一个具体的值2.在信号量当前值的基础上加上一个数值3.在信号量当前值的基础上减上一个数值4.等待信号量的值为 01.
    
  • 一般信号量分为二值信号量与计数信号量

1.二值信号量:一般指的是信号量的值为1,可以理解为只对应一个资源
2.计数信号量:一般指的是值大于等于2 ,可以理解为对应多个资源
  • 在 Linux 系统中查询信号量使用ipcs -s
    在这里插入图片描述

在这里插入图片描述

4.创建信号量

创建信号量集合调用semget函数

1.函数原型
int semget(key_t key, int nsems, int semflg);
2.函数头文件
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
2.函数功能
创建一个信号量集合
3.函数参数
key:ftok()函数生成
nsems:信号量的数量
semflg:信号量集合的标志IPC_CREAT:创建标志IPC_EXCL:与IPC_CREAT标志一起使用,如果信号量集合存在就报错权限标志
4.函数返回值
成功:返回信号量集合的id
失败:-1,并设置errno

5.初始化信号量

初始化信号量调用 semctl 函数

函数头文件
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
函数原型
int semctl(int semid, int semnum, int cmd,);
函数功能
信号量集合控制函数,根据cmd决定当前函数的功能
函数参数
semid:信号量集合的id
semnum:信号量的编号,信号量的编号从0开始
cmd:命令控制字
SETVAL: 设置信号量的值(Set the semaphore value (semval) to arg.val for
the semnum-th semaphore of the set, updating also the sem_ctime member of the
semid_ds structure associated with the set.)
[将信号量值(semval)设置为该集合的第semnum个信号量的arg.val,同时更新与该集合相关联
的semid_ds结构的sem_ctime成员。]
GETVAL: 获取信号量的值
SETALL: Set the semval values for all semaphores of the set using
arg.array,
......
...:后面是属于可变参数列表,根据不同的命令有不同的参数
函数返回值
成功:根据不同的命令有不同的返回值,可以查看帮助文档关于 RETURN 的说明
GETNCNT the value of semncnt
GETPID the value of sempid
GETVAL the value of semval
GETZCNT the value of semzcnt.
All other cmd values return 0 on success.
失败:返回-1,并设置 errno

使用命令时需要使用 union semun 共用体,具体定义如下:

union semun {int val; /* Value for SETVAL *///用的最多struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */unsigned short *array; /* Array for GETALL, SETALL *///用的最多struct seminfo *__buf; /* Buffer for IPC_INFO(Linux-specific) */
};
The semid_ds data structure is defined in <sys/sem.h> as follows:
struct semid_ds {struct ipc_perm sem_perm; /* Ownership and permissions */time_t sem_otime; /* Last semop time */time_t sem_ctime; /* Creation time/time of lastmodification via semctl() */unsigned long sem_nsems; /* No. of semaphores in set */
};

6.信号量的操作

信号量可以进行以下操作:

  • 对信号量可以进行以下操作:
  • 对信号量的值减1
  • 等待信号量的值为0

操作信号量调用semop函数

1.函数头文件
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
2.函数原型
int semop(int semid, struct sembuf *sops, size_t nsops);
3.函数功能
信号量操作函数,用于占用信号量、释放信号量、设置信号量等待
4.函数参数
semid:信号量集合id
sops:信号量操作结构体指针
nsops:操作的信号量的数量
5.函数返回值
成功:返回 0
失败:返回-1,并设置errno

struct sembuf 结构体

sements of this structure are of type struct sembuf, containing the following
members:unsigned short sem_num; /* semaphore number */short sem_op; /* semaphore operation */short sem_flg; /* operation flags */

说明:

sem_num:信号量编号,0开始
sem_op:信号量操作-1:占用资源+1:释放资源0:等待资源
sem_flg:信号量操作标志IPC_NOWAIT:非阻塞,在信号量的值为0,会立即返回SEM_UNDO:在进程终止时,会自动释放信号量

7.信号量集合删除:

信号量集合调用 semctl 函数,设置命令为 IPC_RMID

int semctl(int semid, int semnum, int cmd, ...);

在这里插入图片描述
使用方式:

int ret=semctl(semid,0,IPC_RMID,NULL);

8.信号量数组测试案列(使用信号量解决父子进程对终端的竞争)

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#define PATHNAME "./"
#define PATHNUMBER 68
union semun{unsigned short *array;
};
//创造信号量
int sem_create(int nsems){key_t key = ftok(PATHNAME,PATHNUMBER);if(key == -1){perror("key");exit(EXIT_FAILURE);}int semid = semget(key,nsems,0644 | IPC_CREAT);if(semid == -1){perror("semid");exit(EXIT_FAILURE);} union semun sem;unsigned short arr[1] = { 1 };sem.array = arr;int figure = semctl(semid,0,SETALL,sem);if(figure == 1){perror("figure");exit(EXIT_FAILURE);}return semid;
}
//占据信号量数组
void sem_occupy(int semid,int operation_id){struct sembuf sops;sops.sem_num = operation_id;sops.sem_op = -1;//占据资源sops.sem_flg = SEM_UNDO;//进程终止时,会释放资源int ret = semop(semid,&sops,1);if(ret == -1){perror("ret");exit(EXIT_FAILURE);}
}
//释放信号量数组
void sem_release(int semid,int operation_id){struct sembuf sops;sops.sem_num = operation_id;sops.sem_op = 1;//释放资源sops.sem_flg = SEM_UNDO;//进程终止时,会释放资源int ret = semop(semid,&sops,1);if(ret == -1){perror("ret");exit(EXIT_FAILURE);}       }
int main(){int semid = sem_create(1);int pid = fork();if(pid == -1){perror("pid");exit(EXIT_FAILURE);}else if(pid > 0){while(1){sem_occupy(semid,0);printf("parent start\n");printf("parent end\n");sleep(2);sem_release(semid,0);}}else if(pid == 0){while(1){sem_occupy(semid,0);printf("son start\n");printf("son end\n");sleep(2);sem_release(semid,0); }}return 0;
}

9.信号量之间的同步

在这里插入图片描述
实现思路:

  • 通过创建一个信号量集合,包含 2个信号量,一个信号量编号为0**(SEM_CONTROL_P)控制父进程的运行与暂停,一个信号量编号为1(SEM_CONTROL_C)**控制子进程的运行与暂停

  • 控制逻辑
    在这里插入图片描述

  • 信号初始化

    1. SEM_CONTROL_P : 初始化为 0
    2. SEM_CONTROL_C : 初始化为 1
  • 子进程

占用 SEM_CONTROL_C ,此时子进程阻塞
当父进程释放 SEM_CONTROL_C 时, 子进程开始工作 ,释放 SEM_CONTROL_P
循环占用 SEM_CONTROL_C,由于之前已经占用,此时进入子进程阻塞,等待父进程释放SEM_CONTROL_C
  • 父进程
    占用 SEM_CONTROL_P,此时父进程正常运行,运行程序
    释放 SEM_CONTROL_C,占用 SME_CONTROL_P,此时父进程阻塞,子进程继续执行
    当子进程输出 B 之后,释放 SEM_CONTROL_P,父进程继续执行,运行进程
    父进程释放 SEM_CONTROL_P 循环结束

父子进程的同步的案例(c语言) :

任务:创建一个子进程,将当前系统时间按照 1.<2024-2-5 14:30:29> 格式写入到文件中
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#define PATHNAME "./"
#define PATHNUMBER 67
#define PATH "./log.txt" 
union semun{unsigned short *array;
};
#define SEM_CONTROL_P 0
#define SEM_CONTROL_S 1 
//创造信号量
int sem_create(int nsems){key_t key = ftok(PATHNAME,PATHNUMBER);if(key == -1){perror("key");exit(EXIT_FAILURE);}int semid = semget(key,nsems,0644 | IPC_CREAT);if(semid == -1){perror("semid");exit(EXIT_FAILURE);} union semun sem;unsigned short arr[2] = { 1,0 };sem.array = arr;int figure = semctl(semid,0,SETALL,sem);if(figure == -1){perror("figure");exit(EXIT_FAILURE);}return semid;
}
//占据信号量数组
void sem_occupy(int semid,int operation_id){struct sembuf sops;sops.sem_num = operation_id;sops.sem_op = -1;//占据资源sops.sem_flg = SEM_UNDO;//进程终止时,会释放资源int ret = semop(semid,&sops,1);if(ret == -1){perror("ret");exit(EXIT_FAILURE);}
}
//释放信号量数组
void sem_release(int semid,int operation_id){struct sembuf sops;sops.sem_num = operation_id;sops.sem_op = 1;//释放资源sops.sem_flg = SEM_UNDO;//进程终止时,会释放资源int ret = semop(semid,&sops,1);if(ret == -1){perror("ret");exit(EXIT_FAILURE);}       }
int main(){int semid = sem_create(2);int pid = fork();FILE* pf = fopen(PATH,"a+");if(pf == NULL){perror("pf:");exit(EXIT_FAILURE);}if(pid == -1){perror("pid");exit(EXIT_FAILURE);}else if(pid > 0){while(1){sem_occupy(semid,SEM_CONTROL_P);fprintf(pf,"%s","1.<");fflush(pf);sem_release(semid,SEM_CONTROL_S);sem_occupy(semid,SEM_CONTROL_P);fprintf(pf,"%s\n",">");fflush(pf);printf("输入文件成功\n");sleep(2);sem_release(semid,SEM_CONTROL_P);}}else if(pid == 0){while(1){sem_occupy(semid,SEM_CONTROL_S);time_t timep;struct tm *p;time(&timep);p=gmtime(&timep);char time[128] = { 0 }; sprintf(time,"%d-%d-%d %d:%d:%d",1900 +p->tm_year,1+p->tm_mon,p->tm_mday,8 + p->tm_hour,p->tm_min,p->tm_sec);printf("%s\n",time);fprintf(pf,"%s",time);fflush(pf);sem_release(semid,SEM_CONTROL_P);} }return 0;
}

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

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

相关文章

【项目管理进阶】风险问题

前言 各位盆友&#xff0c;你们期待的项目管理进阶系列有新的消息&#xff0c;请注意查收&#xff0c;并反馈哦~ 在参加项目的过程中&#xff0c;你是否面临或参加过类似如下的场面&#xff1a; 为了立项&#xff0c;先调研市场、技术、社会、组织内部的现状为了科学的管理项目…

2024年中国研究生数学建模竞赛C题数据驱动下磁性元件的磁芯损耗建模 思路讲解

第一题是非常经典的机器学习分类过程, 首先第一步,我们需要做可视化分析。通过一些统计学方法来分析磁通密度的分布特征以及不同波形的一个形态特征,那这里可以通过绘制一些例如核密度估计图,双变量影响关系图,描述性统计等等, 其次,第二步,我们需要去构建特征筛选。…

安科瑞产品在银行智慧用电监测平台的设计与应用

01前言 随着科技发展&#xff0c;电力供应日益充分&#xff0c;电气设备日益增多&#xff0c;电力在带来光明和效率同时&#xff0c;也带来火灾危害。据应急管理部消防救援局统计[1]&#xff0c;2020年全国共接报火灾25.2万起&#xff0c;电气类原因继续强力影响火灾走势&…

漏洞——CVE简介

1、什么是CVE CVE (Common Vulnerabilities and Exposures)&#xff08;常见漏洞与暴露&#xff09;是一个标准化的命名系统&#xff0c;用于识别和描述公开披露的网络安全漏洞。CVE 的目的是为漏洞提供唯一的标识符&#xff0c;使安全专家、软件供应商和用户能够统一参考和讨…

Java+Spring Cloud +UniApp 智慧工地源码,用户PC端、移动端数据同步,支持多端展示

数字化给各行各业所带来的改变&#xff0c;在早些年间突出自动这一流程。但随着科技的发展&#xff0c;让人们也愈发了解可视化操作所带来的优势。智慧工地的诞生&#xff0c;相当于为建筑施工带来了一套较为完整的数字化流程&#xff0c;能够完善施工环节中的各部分内容。接下…

CTFshow--爆破靶场全攻略

前言 欢迎来到我的博客 个人主页:北岭敲键盘的荒漠猫-CSDN博客 本文主手把手详细整理ctfshow中爆破的攻略 web21 打开页面发现要输入密码 观察数据包 401未授权 我们随便输入密码试试 再观察数据包 乍一看好像这个get没有任何参数 但是仔细看的话会发现多了一个明显为base64…

工程师 - Windows下使用WSL本地安装Linux

Setting Up to Use Windows Subsystem For Linux (WSLv2) 1&#xff0c;WinR&#xff0c;运行ver命令&#xff1a; 我的是Win11系统&#xff0c;但版本还是10.xx的。要求 Windows 10 builds > 18917&#xff0c;才能使用WSLv2。 如果需要版本升级&#xff0c;请参照&#xf…

C++进阶|多态知识点详解及经典面试题总结

&#x1f36c; mooridy-CSDN博客 &#x1f9c1;C专栏&#xff08;更新中&#xff01;&#xff09; 目录 1. 多态的概念 2. 多态的定义及实现 2.1 多态的构成条件 2.2 虚函数的重写/覆盖 2.3 虚函数重写的⼀些其他问题 2.4 override 和 final关键字 2.5 重载/重写/隐藏的…

★pwn 更改pwn题libc保姆级教程★

★pwn 更改pwn题libc保姆级教程★ &#x1f35a;前言&#x1f95f;安装&#x1f95f;glibc-all-in-one下载与调整libc&#x1f95f;patchelf更改libc&#x1f95f;clibc的使用与分析 &#x1f35a;前言 现在市面上有很多关于改libc的教程&#xff0c;但是基本有以下几个问题&a…

C++初阶-list用法总结

目录 1.迭代器的分类 2.算法举例 3.push_back/emplace_back 4.insert/erase函数介绍 5.splice函数介绍 5.1用法一&#xff1a;把一个链表里面的数据给另外一个链表 5.2 用法二&#xff1a;调整链表当前的节点数据 6.unique去重函数介绍 1.迭代器的分类 我们的这个迭代器…

查找算法 02折半查找

自己设计一个折半查找的例子,不少于10个数据元素,画出对应的查找分析树 基于上述例子&#xff0c;计算查找成功的ASL、查找失败的ASL 又称二分查找&#xff0c;仅适用于有序的顺序表。

python --PyAibote自动化

官文: https://www.pyaibote.com/ 下载安卓集成环境: 可以看到开发的一些信息

在线免费公共DNS解析服务器列表

115站长工具网公共DNS栏目推荐阿里DNS、百度DNS、Google免费DNS地址、OpenDNS地址库、114 DNS、DNSPod等

大数据最新面试题(持续更新)

2024大数据面试题 什么是Hbase&#xff1f;它与Hadoop的关系是什么&#xff1f; Hbase是一个开源的分布式数据库&#xff0c;基于Hadoop的HDFS&#xff0c;用于大数据存储和处理。它提供了高性能的读写能力和可扩展性。 Hbase的架构是什么&#xff1f; Hbase的架构由Region…

传统美业通过小魔推短视频矩阵系统,实现逆势增长?

许多美甲店在经营过程中常常陷入一个误区&#xff1a;他们认为自己缺少的是客户&#xff0c;但实际上&#xff0c;他们真正缺少的是有效的营销策略&#xff0c;美甲店经营者普遍面临的两大难题包括&#xff1a; 1. 高客户流失率&#xff1a; 据研究显示&#xff0c;约70%的顾…

“一屏显江山”,激光显示重构「屏中世界」

【潮汐商业评论/原创】 2024年国庆期间&#xff0c;曾感动过无数国人的舞蹈诗剧《只此青绿》改编的同名电影即将上映&#xff0c;而这一次观众们不必走进电影院&#xff0c;在家里打开官方合作的海信激光电视也能享受到同等的视听效果&#xff0c;这是激光电视在观影场景领域的…

基于yolov5和openpose人体骨骼关键点实现的摔倒姿态识别检测系统实现

【参考源码】 https://github.com/HRonaldo/Openpose_YOLO 本项目参考上面框架进行全面改进&#xff0c;改进如下&#xff1a; &#xff08;1&#xff09;封装YOLOv5检测类&#xff0c;这样可以加强阅读便利性&#xff0c;模块设计方便嵌入其他框架&#xff0c;后面我会换成…

2. qgis c++ api 整体框架详解

转载 2. qgis c api 整体框架详解-CSDN博客 整体架构 QGis库官方文档 下表是官方文档中的模块说明&#xff1a; 其中3D&#xff0c;QgsQuick和server库需要在编译之前进行配置&#xff0c;配置项分别为WITH_3D WITH_QUICK和WITH_SERVER&#xff0c;具体编译配置方法见开发环…

祝天下老师教师节快乐-HTML+java script

效果图 &#x1f680;HTML结构揭秘&#x1f680;: &#x1f4dd;<head>中包含了元信息和样式表。 &#x1f5bc;️<body>拥有一个<canvas>元素与一个.text类的<div>&#xff0c;为星空与教师节信息搭建舞台。 &#x1f3a8;CSS魔法调色盘&#x1f3a…

计算机网络:物理层 --- 基本概念、编码与调制

目录 一. 物理层的基本概念 二. 数据通信系统的模型 三. 编码 3.1 基本概念 3.2 不归零制编码 3.3 归零制编码 3.4 曼切斯特编码 3.5 差分曼切斯特编码 ​编辑 四. 调制 4.1 调幅 4.2 调频 4.3 调相 4.4 混合调制 今天我们讲的是物理…