进程间通信----信号量

文章目录

  • 信号量
    • 1. 问题
    • 2. 什么是信号量
    • 3. 信号量的使用
    • 4. 信号量的控制
    • 6. 实例

信号量

1. 问题

  • 程序中,有时存在一种特殊代码,最多只允许一个进程执行该部分代码。这部分区域,称为“临界区”

  • 然而在多进程并发执行时,当一个进程进入临界区,我们可以使用信号量让别的进程不能进入。

2. 什么是信号量

信号量,是一种特殊的变量:只能对信号量执行P操作和V操作

  • P操作(要执行代码的时候): 如果信号量的值 == 0, 则挂起该进程,如果信号量的值 > 0, 则把该信号量减1
  • V操作(执行完代码的时候): 如果有进程因该信号量而被挂起,则恢复该进程运行,如果没有进程因该信号量而挂起,则把该信号量加1
  • 注意:P操作、V操作都是原子操作,即其在执行时,不会被中断。

注意:此指的“信号量”是指System V IPC的信号量,与线程所使用的信号量不同。该信号量,用于进程间通信。

文件锁,只能有一个对文件进行操作
当信号量 只为 0/1 的时候,有点向文件锁,只能有一个进程对“临界区”操作

我的简单理解:int num = 5;当我要进入“临界区”中的代码的时候,num --,当退出“临界区”的时候num++,

当我们要进入“临界区”的时候,num > 0,否则就阻塞

3. 信号量的使用

  1. 信号量的获取
  • 原型:int semget(key_t key, int nsems, int semflg);

  • 功能:获取一个已存在的、或创建一个新的信号量量,返回该信号量的标识符

  • 参数:

    • key, 键值,该键值对应一个唯一的信号量。类似于共享内存的键值。不同的进程可通过该键值和semget获取唯一的信号量。特殊键值:IPC_PRIVAT该信号量只允许创建者本身, 可用于父子进程间通信。
    • nsems, 需要的信号量数目,一般取1
    • sem_flags, 与共享内存的sem_flags类似。IPC_CREAT, 如果该信号量未存在,则创建该信号量如果该信号量已存在,也不发送错误。
  • 返回值: 成功,则返回一个正数,失败, 返回返回-1

  1. 信号量的操作
  • 原型:int semop(int semid, struct sembuf *sops, unsigned nsops);
  • 功能:改变信号量的值,即对信号量执行P操作、或V操作。
  • 参数:
    • semid, 信号量标识符, 即semget的返回值
    • sops, 是一个数组,元素类型为struct sembuf
 struct sembuf {
         short  sem_num;  //信号量组中的编号(即指定对哪个信号量操作)
                          //semget实际是获取一组信号量
                          //如果只获取了一个信号量,则该成员取0
         short  sem_op;   //   -1,  表示P操作
                          //   1,  表示V操作
         short  sem_flg;  // SEM_UNDO : 如果进程在终止时,没有释放信号量
                          // 如果不设置指定标志,应该设置为0则,自动释放该信号量                     
     }        
    • nsops, 表示第二个参数sops所表示的数组的大小,即表示有几个struct sembuf
  • 返回值: 失败, 返回-1,成功, 返回 0

4. 信号量的控制

  • 原型:int semctl(int semid, int sem_num, int cmd, …);

  • 功能:对信号量进行控制

  • 参数:

    • semid, 信号量标识符
    • sem_num, 信号量组中的编号,如果只有一个信号量,则取0
    • cmd, SETVAL 把信号量初始化为指定的值,具体的值由第4个参数确定
  • 注意:只能对信号量初始化一次,如果在各进程中,分别对该信号量进行初始化,则可能导致错误!

  • IPC_RMID 删除信号量

//参数4, 类型为:
union  semun {
	int val;      // SETVAL命令要设置的值
    struct semid_ds *buf;
    unsigned short *array;
}

注意:union semun类型要求自己定义有些Linux发行版在sys/sem.h中定义,有些发行版则没有定义。

可自定义如下:

#if defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED)						   
#else
	union semun {
		int val;                             
		struct semid_ds *buf;    
		unsigned short int *array; 
		struct seminfo *__buf;  
};
#endif   

6. 实例

实例1:不使用信号量,并发执行多个进程,观察对临界区的访问。
main1.c
#include <stdlib.h>
#include <stdio.h>

int main(void) 
{
	int i;
    pid_t pd = fork();
	for (i=0; i<5; i++) {
		/* 模拟临界区----begin */
		printf("Process(%d) In\n", getpid());		
		sleep(1);
		printf("Process(%d) Out\n", getpid());
        /* 模拟临界区----end */ 
		sleep(1);
	}
	return 0;
}

现象:父子进程可以同时执行 ”临界区“

实例2:使用信号量,并发执行多个进程,观察对临界区的访问。main2.c (对main1.c改进)
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdlib.h>
#include <stdio.h>

#if defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED)						   
#else
    union semun {
        int val;                             
        struct semid_ds *buf;    
        unsigned short int *array; 
        struct seminfo *__buf;  
    };
#endif     

static sem_initial(int semid) 
{
	int ret;
	
	union semun semun;
	semun.val = 1;// 把信号量置为1
	ret = semctl(semid, 0, SETVAL, semun); // 设置信号量
	if (ret == -1) {
		fprintf(stderr, "semctl failed!\n");
	}
	
	return ret;
}

static int  sem_p(int semid)
{
	int ret;
	
	struct sembuf sembuf;
	sembuf.sem_op = -1;
	sembuf.sem_num = 0;
	sembuf.sem_flg = SEM_UNDO;
	ret = semop(semid, &sembuf, 1);	
	if (ret == -1) {
		fprintf(stderr, "sem_p failed!\n");
	}
	
	return ret;
}

static int  sem_v(int semid)
{
	int ret;
	
	struct sembuf sembuf;
	sembuf.sem_op = 1;
	sembuf.sem_num = 0;
	sembuf.sem_flg = SEM_UNDO;
	ret = semop(semid, &sembuf, 1);	
	if (ret == -1) {
		fprintf(stderr, "sem_v failed!\n");
	}
	
	return ret;
}

int main(int argc, char* argv[]) 
{
	int i;
	int ret;
	int semid;


	/* 获取信号量 */
	semid = semget((key_t)1234, 1, 0666 | IPC_CREAT);
	if (semid == -1) {
		printf("semget failed!\n");
		exit(1);
	}

	/* 初始化信号量 */
	if (argc > 1) {
		ret = sem_initial(semid);
		if (ret == -1) {
			exit(1);
		}
	}

	for (i=0; i<5; i++) {

                // 先执行P操作
		if (sem_p(semid) == -1) {
			exit(1);
		}
		
		/* 模拟临界区----begin */
		printf("Process(%d) In\n", getpid());		
		sleep(1);
		printf("Process(%d) Out\n", getpid());
              /* 模拟临界区----end */ 
                // 再执行V操作
		if (sem_v(semid) == -1) {
			exit(1);
		}
			  
		sleep(1);
	}

    /* 删除信号量 */
	   
	return 0;
}

两个终端都执行上面的程序,两个程序交替拿到信号量,则交替执行信号量之间的程序
信号量专治多进程

在这里插入图片描述

练习:

  • 使用信号量实现对文件操作的互斥访问。
  • 程序1,对test.txt写入学生记录信息10条
  • 程序2,对test.txt写入教师记录信息10条
  • 程序1和程序2并发执行

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

GPIO的八种模式分析

GPIO是general purpose input output,即通用输入输出端口&#xff0c;作用是负责外部器件的信息和控制外部器件工作。 GPIO有如下几个特点&#xff1a;1.不同型号的IO口数量不同&#xff1b;2&#xff0c;反转快速&#xff0c;每次翻转最快只需要两个时钟周期&#xff0c;以ST…

【数据结构篇C++实现】- 栈

文章目录&#x1f680;一、栈的原理精讲&#x1f680;二、栈的算法实现⛳栈的顺序存储结构&#x1f389;&#xff08;一&#xff09;顺序栈1.栈的结构体定义2.栈的初始化3.判断空栈4.判断栈满5.元素入栈6.元素出栈7.获取栈顶元素&#x1f389;&#xff08;二&#xff09;共享栈…

dolphinscheduler 2.0.6 资源中心改造方案二:通过NFS挂载共享目录

目录调度资源中心存储概要安装NFS服务器客户端调度验证关闭SFTP开关&#xff08;可忽略&#xff09;重新上传资源文件worker执行任务验证服务器woker客户端worker其它nfs共享目录的配置文件/etc/exports说明调度资源中心存储概要 针对现有的单机存储可以做哪些扩展&#xff1f;…

Warshall算法

&#x1f680;write in front&#x1f680; &#x1f4dc;所属专栏&#xff1a;> 算法 &#x1f6f0;️博客主页&#xff1a;睿睿的博客主页 &#x1f6f0;️代码仓库&#xff1a;&#x1f389;VS2022_C语言仓库 &#x1f3a1;您的点赞、关注、收藏、评论&#xff0c;是对我…

JavaScript-扫盲

文章目录1. 前言2. 第一个 JavaScript 程序3. javaScript 的基础语法3.1 变量3.2 数据类型3.3 运算符3.4 条件语句3.5 数组3.6 函数3.7 作用域3.8 对象4. WebAPI4.1 DOM 基本概念4.2 常用 DOM API4.3 事件4.4 操作元素4.5 网页版猜数字游戏4.6 留言版1. 前言 提问 java 和 java…

Elasticsearch 核心技术(六):内置的 8 种分词器详解 + 代码示例

❤️ 博客主页&#xff1a;水滴技术 &#x1f680; 支持水滴&#xff1a;点赞&#x1f44d; 收藏⭐ 留言&#x1f4ac; &#x1f338; 订阅专栏&#xff1a;大数据核心技术从入门到精通 文章目录一、内置分词器1. Standard&#xff08;标准分词器&#xff09;英文示例中文示例…

Flink学习笔记(六)Time详解

一、Flink中Time的三种类型&#xff1a; Stream数据中的Time&#xff08;时间&#xff09;分为以下3种&#xff1a; 1.Event Time&#xff08;事件产生的时间&#xff09;&#xff1a; 事件的时间戳&#xff0c;通常是生成事件的时间。Event time 是事件本身的时间&#xff0c…

整理了一份github上比较热门的ChatGPT项目,值得收藏

ChatGPT已经火了一段时间了&#xff0c;但是&#xff0c;热度依旧是各大自媒体的热榜。由于&#xff0c;国内不能直接访问ChatGPT,国内的开发者依托OpenAI的接口&#xff0c;开发出一些ChatGPT的应用。今天就整理一下github上最热门的ChatGPT项目。 lencx/ChatGPT 该项目是Cha…

stm32学习笔记-10 I2C通信

10 I2C通信 文章目录10 I2C通信10.1 I2C通信10.2 MPU6050简介10.3 实验&#xff1a;软件读写MPU605010.4 I2C外设简介10.5 实验&#xff1a;硬件I2C读写MPU6050注&#xff1a;笔记主要参考B站 江科大自化协 教学视频“STM32入门教程-2023持续更新中”。 注&#xff1a;工程及代…

STM32 KEI 调试新手注意事项

记录一下解决问题的经过:1&#xff0c;用STM32 cubeMX 生成的MKD工程,默认的代码优化级别是level3 &#xff0c; 这个级别 会把一些代码给优化掉&#xff0c;造成一些意想不到的结果&#xff0c;最直观的就是 被优化的语句不能打断点调试&#xff0c;当你打了断点 &#xff0c;…

2020年第十一届C/C++ B组第一场蓝桥杯省赛真题

准备参加第十四届蓝桥杯&#xff0c;今天开始刷题目的第一天&#xff0c;下面是2020年第十一届C/C B组第一场蓝桥杯省赛真题&#xff0c;以下是我的做题目心得。跑步训练第一次写的代码失误点如下&#xff1a;第一个错误点是因为好久没有写代码&#xff0c;忘记判断对才能循环&…

代码质量提升,代码扫描 review 之 Codacy 工具使用

目录一、什么是Codacy二、GitHub 上使用 Codacy三、Codacy上导入GitHub项目一、什么是Codacy Codacy 是用于代码 review 检测(即代码审查)的工具&#xff0c;目前支持对40多种编程语言检测&#xff0c;如 c、c、c#、java 、python、javascript 等。 Codacy 可用于 GitHub 和 …

信息系统项目管理师第四版知识摘编:第9章 项目范围管理

第9章 项目范围管理 项目范围管理包括确保项目做且只做所需的全部工作&#xff0c;以成功完成项目。项目范围管理主要在于定义和控制哪些工作应该包括在项目内&#xff0c;哪些不应该包含在项目内。 9.1管理基础 9.1.1产品范围和项目范围 产品范围&#xff1a;指某项产品、服…

【Linux】进程理解与学习Ⅳ-进程地址空间

环境&#xff1a;centos7.6&#xff0c;腾讯云服务器Linux文章都放在了专栏&#xff1a;【Linux】欢迎支持订阅&#x1f339;相关文章推荐&#xff1a;【Linux】冯.诺依曼体系结构与操作系统【Linux】进程理解与学习Ⅰ-进程概念浅谈Linux下的shell--BASH【Linux】进程理解与学习…

冯诺依曼,操作系统以及进程概念

文章目录一.冯诺依曼体系结构二.操作系统&#xff08;operator system&#xff09;三.系统调用和库函数四.进程1.进程控制块&#xff08;PCB&#xff09;2.查看进程3.系统相关的调用4.fork介绍&#xff08;并发引入&#xff09;五.总结一.冯诺依曼体系结构 计算机大体可以说是…

Chat GPT介绍

一、Chat GPT是什么&#xff1f; ChatGPT是一个基于大规模预训练语言模型的对话系统&#xff0c;由OpenAI开发。它的核心技术是GPT&#xff08;Generative Pre-trained Transformer&#xff09;模型&#xff0c;是一种基于深度学习的自然语言处理技术。GPT模型采用Transformer…

推荐人工智能领域十大类专业好用的深度学习预训练模型

深度学习领域出现了许多优秀的预训练模型。以下是一些常用的专业深度学习预训练模型: 图像分类模型: VGG(Visual Geometry Group)系列:VGG16、VGG19等 ResNet(Residual Network)系列:ResNet50、ResNet101等 Inception(Google Inception)系列:InceptionV3、Incepti…

2022财报逆转,有赞穿透迷雾实现突破

2022年&#xff0c;商家经营面临困难。但在一些第三方服务商的帮助下&#xff0c;也有商家取得了逆势增长。 2023年3月23日&#xff0c;有赞发布2022年业绩报告&#xff0c;它帮助许多商家稳住了一整年的经营。2022年&#xff0c;有赞门店SaaS业务的GMV达到425亿元&#xff0c…

简单XXE漏洞理解以及在实战中演练【网络安全】

1.概念 XXE(XML External Entity Injection) 全称为 XML 外部实体注入。这是一个注入漏洞&#xff0c;强调利用点是外部实体 &#xff0c;将注意力集中于外部实体中&#xff0c;而不要被 XML 中其他的一些名字相似的东西扰乱了思维&#xff0c;如果能注入 外部实体并且成功解析…

Springboot项目如何实现mybatis的流式查询

前言 mybatis的流式查询&#xff0c;有点冷门&#xff0c;实际用的场景比较少&#xff0c;但是在某些特殊场景下&#xff0c;却是十分有效的一个方法。很多人没有听说过&#xff0c;实际上是对mybatis没有太重视&#xff0c;对mybatis想法还停留一个dao接口对应着mapper里的一个…
最新文章