Linux下多进程通信(signal,pipe)

2023-11-11

操作系统实验导航
实验一:银行家算法 https://blog.csdn.net/weixin_46291251/article/details/115384510
实验二:多级队列调度和多级反馈队列调度算法 https://blog.csdn.net/weixin_46291251/article/details/115530582
实验三:动态分区式内存管理 https://blog.csdn.net/weixin_46291251/article/details/115772341
实验四:Linux下多进程通信 https://blog.csdn.net/weixin_46291251/article/details/116274665
实验五:进程通信的三种方式 https://blog.csdn.net/weixin_46291251/article/details/116301250
实验六:Linux文件系统实验 https://blog.csdn.net/weixin_46291251/article/details/116423798
实验七:自制简单U盘引导程序 https://blog.csdn.net/weixin_46291251/article/details/116427629
实验八:磁盘调度算法 https://blog.csdn.net/weixin_46291251/article/details/116431907
实验九:请求分页系统中的置换算法 https://blog.csdn.net/weixin_46291251/article/details/116443021
学习笔记:操作系统复习笔记 https://blog.csdn.net/weixin_46291251/article/details/117086851

题目描述:

  • 父进程使用系统调用pipe()建立一个管道,然后使用系统调用fork()创建两个子进程:子进程1和子进程2
  • 子进程1每隔1秒通过管道向子进程2发送数据:I send message x times.(x初值为1,以后发送一次后做加一操作)
  • 子进程2从管道读出信息,并显示在屏幕上
  • 父进程用系统调用signal()来捕捉来自键盘的中断信号SIGINT(即按Ctrl+C键,);当捕捉到中断信号后,父进程用系统调用kill()向两个子进程发出信号,
  • 子进程捕捉到信号后分别输出如下信息后终止:
    Child Process 1 is killed by Parent!
    Child Process 2 is killed by Parent!
  • 父进程等待两个子进程终止后,释放管道并输出如下的信息后终止
    Parent Process is Killed!

算法设计:

多进程:

这里主要是利用系统调用fork:

  • fork是Linux下创建进程的一个系统调用
    调用fork的进程为主进程,一次调用会产生一个子进程。
  • fork的特点:一次调用两次返回:
    主进程和子进程的差异就从fork这条语句开始,fork给调用他的主进程的返回值是子进程的PID (若成功),给子进程的返回值是0,故可由此判断当前进程是子进程还是父进程,如:
int pid = fork();
if(pid==0){
//说明是子进程,这里写子进程的相关操作
}
else{
//说明是父进程,这里写父进程的相关操作
}
如何创建多个子进程?

错误的方法:

for(int i=0;i<10:i++)
	fork();

这显然不正确,因为不仅有父进程可以执行fork()语句,子进程也能执行,这就会导致实际创建的进程比预期的要多,因为有类似子进程的子进程存在。
避免这个问题也很简单,只在父进程执行fork()就行了,区分父子进程的方法上面已经给出。
我的具体实现代码:

int childpid[10];//用来保存所有进程的PID,0号是主进程
childpid[0]=getpid();//012分别是父进程和两个子进程的pid
for(int i=1;i<=2;i++){
		int pid=fork();
		if(pid!=0)
			childpid[i] =pid;
		else{
			childpid[i] =getpid();
			break;
		}
	}
最终,主程序的逻辑大概如下:

if(getpid()==childpid[0]){
}
if(getpid()==childpid[1]){
}
if(getpid()==childpid[2]){
}


信号机制:
信号是在软件层次上对中断机制的一种模拟,是一种异步通信方式

使用signal()函数处理时,只需指出要处理的信号处理函数即可。
signal()原型:
/*signal-handler*/* signal(int sig, /*signal-handler*/* handler);

  • 参数:
    sig:要设置信号处理函数的信号。它可以是实现定义值或预定义的宏(见下方):
    handler:信号处理函数。这必须是下列之一:
      SIG_DFL 宏。信号处理函数被设为默认信号处理函数。
      SIG_IGN 宏。忽略信号。
      指向函数指针。
  • 返回值
    成功时为先前的信号处理函数,失败时为 SIG_ERR (某些实现上能禁用设置信号处理函数)。
  • 信号处理函数的预定义宏

SIGINT:ctrl+c 终止信号   
SIGQUIT:ctrl+\ 终止信号   
SIGTSTP:ctrl+z 暂停信号
SIGALRM:闹钟信号 收到此信号后定时结束,结束进程   
SIGCHLD:子进程状态改变,父进程收到信号   
SIGKILL:杀死信号

  • 用户进程对信号的响应方式:
      忽略信号(利用SIG_IGN 宏)
      捕捉信号
      执行缺省操作

  • 其他需要的相关函数:

int kill(pid_t pid, int sig);
  功能:发送信号
  参数:pid:指定进程
     sig:要发送的信号
  返回值:成功 0;失败 -1
这里需要用到几个函数:

程序功能的具体实现:
  • 1.父进程接收Ctrl+C信号
signal(SIGINT,fun_pare);//发出中断信号
  • 2.父进程响应Ctrl+C:向子进程发出信号
void fun_pare(int sig)//父进程响应Ctrl C 信号函数
{
	kill(childpid[1],SIGUSR1);
	kill(childpid[2],SIGUSR2);
}
  • 3.子进程接收父进程发来的信号
		signal(SIGUSR1,fun_chid);
		signal(SIGUSR2,fun_chid);

注意在子进程中应该屏蔽Ctrl+C信号,否则,在父进程响应Ctrl+C时,子进程就会调用默认的响应函数而退出了:

signal(SIGINT,SIG_IGN);
  • 4.子进程对父进程发来的信号进行处理
void fun_chid(int sig)//子进程1响应信号函数
{
	if(sig==SIGUSR1)
		printf("\nChild Process 1 is killed by parent!\n");
	if(sig==SIGUSR2)
	printf("\nChild Process 2 is killed by parent!\n");
		
	exit(822);//默认正常退出返回0
}

这里利用响应函数的参数对接收到的函数进行判断,从而将两个进程的响应放在一块实现。

管道通信:
  • pipe函数的原型:
    int pipe (int fd[2]); //成功返回0,出错返回-1
    fd参数是数组/指针,可以带回两个值(文件描述符),
    fd[0]指向管道的读端,fd[1]指向管道的写端。fd[1]的输出是fd[0]的输入。

  • pipe通信(父子进程间)的流程:
    1.父进程创建管道,得到两个件描述符指向管道的两端
    2.发进程关闭fd[1](读端),利用write()向管道写入
    3.收进程关闭fd[0](写端),利用read()从管道读出

  • 我这里的实现:

	int flg,fd[2];
	flg = pipe(fd); //创建管道
    if (flg == -1)
        perror("pipe error");
    
    int *child,*msg,len;
	write(fd[1],child,len);//表示向fd[1]写入child字符串的前len位
	read(fd[0],msg,sizeof(msg))//表示从fd[0]读出一个字符串

整体实现代码:


#include <signal.h>
#include <sys/wait.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>


int childpid[10]={-1,-1,-1,-1},status=999;

    

void fun_pare(int sig)//父进程响应Ctrl C 信号函数
{
	kill(childpid[1],SIGUSR1);
	kill(childpid[2],SIGUSR2);
}
void fun_chid(int sig)//子进程1响应信号函数
{
	if(sig==SIGUSR1)
		printf("\nChild Process 1 is killed by parent!\n");
	if(sig==SIGUSR2)
	printf("\nChild Process 2 is killed by parent!\n");
		
	exit(822);//默认正常退出返回0
}


int main(){

	int ret,fd[2];
	ret = pipe(fd); //创建管道
    if (ret == -1)
        perror("pipe error");

	
	

	childpid[0]=getpid();//012分别是父进程和两个子进程的pid

	for(int i=1;i<=2;i++){
		int pid=fork();
		if(pid!=0)
			childpid[i] =pid;
		else{
			childpid[i] =getpid();
			break;
		}
	}


		

	if(getpid()==childpid[0]){//父进程
		printf("我是父进程,PID:%d PPID:%d\n",getpid(),getppid());
		printf("\t子进程1是:PID:%d\n",childpid[1]);
		printf("\t子进程2是:PID:%d\n",childpid[2]);

		signal(SIGINT,fun_pare);//发出中断信号
			
		int child_num = 2;//子进程个数
		while(child_num --){
		int t = wait(&status);//等待两个子进程结束
		printf("一个进程结束了,他的 PID:%d 返回码 :%d\n",t,status);
		}
		

		printf("Parent process is killed!\n");//两个子进程都结束后主进程才可以结束
		exit(822);//默认正常退出返回0
	}
	else{//否则是子进程
		signal(SIGINT,SIG_IGN);
		signal(SIGUSR1,fun_chid);
		signal(SIGUSR2,fun_chid);
	}


	if(getpid()==childpid[1]){//子进程1
		int i=0;
        close(fd[0]);
        char child[100]="I send message x times !\0";
		
        while(++i)
        {
			child[15] = '0' + i;
            write(fd[1],child,strlen(child)+1);
            sleep(1);
        }
	}
	if(getpid()==childpid[2]){//子进程2
	 	close(fd[1]);
        char msg[100];
        while(1)
        {
            if(read(fd[0],msg,sizeof(msg)))
            	printf("%s\n",msg);
        }
	}	
	return 0;
}

运行截图:

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux下多进程通信(signal,pipe) 的相关文章

  • xsel -o 对于 OS X 等效项

    是否有一个等效的解决方案可以在 OS X 中抓取选定的文本 就像适用于 Linux 的 xsel o 一样 只需要当前的选择 这样我就可以在 shell 脚本中使用文本 干杯 埃里克 你也许可以安装xsel在 MacOS 上 更新 根据 A
  • Locale.getDefault() 始终返回 en

    unix 机器上的服务器始终使用 en 作为默认区域设置 以下是区域设置输出 LANG en US LC CTYPE C LC NUMERIC C LC TIME C LC COLLATE C LC MONETARY C LC MESSAG
  • 如何修复“iptables:没有该名称的链/目标/匹配”?

    我在我的 Linux 嵌入式系统上构建并安装了 iptables 如果我列出所有规则 则一切正常 iptables list Chain INPUT policy ACCEPT target prot opt source destinat
  • 拆分字符串以仅获取前 5 个字符

    我想去那个地点 var log src ap kernelmodule 10 001 100 但看起来我的代码必须处理 ap kernelmodule 10 002 100 ap kernelmodule 10 003 101 等 我想使用
  • 何时使用 pthread 条件变量?

    线程问题 看来 只有在其他线程调用 pthread cond notify 之前调用 pthread cond wait 时 条件变量才起作用 如果在等待之前发生通知 那么等待将被卡住 我的问题是 什么时候应该使用条件变量 调度程序可以抢占
  • 强制卸载 NFS 安装目录 [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 Locked 这个问题及其答案是locked help locked posts因为这个问题是题外话 但却具有历史意义 目前不接受新的答案
  • Linux 中的无缓冲 I/O

    我正在写入大量的数据 这些数据数周内都不会再次读取 由于我的程序运行 机器上的可用内存量 显示为 空闲 或 顶部 很快下降 我的内存量应用程序使用量不会增加 其他进程使用的内存量也不会增加 这让我相信内存正在被文件系统缓存消耗 因为我不打算
  • nginx 上的多个网站和可用网站

    通过 nginx 的基本安装 您的sites available文件夹只有一个文件 default 怎么样sites available文件夹的工作原理以及如何使用它来托管多个 单独的 网站 只是为了添加另一种方法 您可以为您托管的每个虚拟
  • Jenkins中找不到环境变量

    我想在詹金斯中设置很多变量 我试过把它们放进去 bashrc bash profile and profile of the jenkins用户 但 Jenkins 在构建发生时找不到它们 唯一有效的方法是将所有环境变量放入Jenkinsf
  • 如何查明CONFIG_FANOTIFY_ACCESS_PERMISSIONS是否启用?

    我想利用fanotify 7 http man7 org linux man pages man7 fanotify 7 html我遇到的问题是在某些内核上CONFIG FANOTIFY ACCESS PERMISSIONS不起作用 虽然C
  • fopen 不返回

    我在 C 程序中使用 fopen 以只读模式 r 打开文件 但就我而言 我观察到 fopen 调用没有返回 它不返回 NULL 或有效指针 执行在 fopen 调用时被阻止 文件补丁绝对正确 我已经验证过 并且不存在与权限相关的问题 任何人
  • Linux 中的动态环境变量?

    Linux 中是否可以通过某种方式拥有动态环境变量 我有一个网络服务器 网站遵循以下布局 site qa production 我想要一个环境变量 例如 APPLICATION ENV 当我在 qa 目录中时设置为 qa 当我在生产目录中时
  • 加载数据infile,Windows和Linux的区别

    我有一个需要导入到 MySQL 表的文件 这是我的命令 LOAD DATA LOCAL INFILE C test csv INTO TABLE logs fields terminated by LINES terminated BY n
  • vector 超出范围后不清除内存

    我遇到了以下问题 我不确定我是否错了或者它是一个非常奇怪的错误 我填充了一个巨大的字符串数组 并希望在某个点将其清除 这是一个最小的例子 include
  • Linux 内核标识符中前导和尾随下划线的含义是什么?

    我不断遇到一些小约定 比如 KERNEL Are the 在这种情况下 是内核开发人员使用的命名约定 还是以这种方式命名宏的语法特定原因 整个代码中有很多这样的例子 例如 某些函数和变量以 甚至 这有什么具体原因吗 它似乎被广泛使用 我只需
  • CentOS:无法安装 Chromium 浏览器

    我正在尝试在 centOS 6 i 中安装 chromium 以 root 用户身份运行以下命令 cd etc yum repos d wget http repos fedorapeople org repos spot chromium
  • Linux:在文件保存时触发 Shell 命令

    我想在修改文件时自动触发 shell 命令 我认为这可以通过注册 inotify 挂钩并调用来在代码中完成system 但是是否有更高级别的 bash 命令可以完成此任务 尝试 inotify 工具 我在复制链接时遇到问题 抱歉 但 Git
  • 如何在apache 2.4.6上安装apxs模块

    我刚刚用过apt get update我的 apache 已更新为2 4 6 我想安装 apxs 来编译模块 但收到此错误 The following packages have unmet dependencies apache2 pre
  • 使用 sh 运行 bash 脚本

    我有 bash 脚本 它需要 bash 另一个人尝试运行它 sh script name sh 它失败了 因为 sh 是他的发行版中 dash 的符号链接 ls la bin sh lrwxrwxrwx 1 root root 4 Aug
  • 有谁知道在哪里定义硬件、版本和序列号。 /proc/cpuinfo 的字段?

    我想确保我的 proc cpuinfo 是准确的 目前它输出 Hardware am335xevm Revision 0000 Serial 0000000000000000 我可以在代码中的哪里更改它以给出实际值 这取决于 Linux 的

随机推荐

  • BES2300Z USB mode 讲解

    hello 在BES的蓝牙中有一些芯片是支持USB mode 在使用的过程中 在BT mode 和 USB mode 中只能有一种模式存在 排版会有点乱 请谅解 下面来讲解下BES2300Z 在USB mode 下打开的方法 遇到的一些问题
  • robotframework安装与详解

    Robot Framework 以下简称rf 是一款python编写的功能自动化测试框架 具备良好的可扩展性 支持关键字驱动 可以同时测试多种类型的客户端或者接口 可以进行分布式测试执行 主要用于轮次很多的验收测试和验收测试驱动开发 ATD
  • Python requests ip代理爬虫报错 HTTPSConnectionPool(host=‘xxxxx‘, port=443) Max retries exceed

    本人系统 macOS10 15 6 Catalina 场景 使用Python requests 包 ip代理池爬取网站数据 出现报错 HTTPSConnectionPool host xxxxx port 443 Max retries e
  • JDBC实现

    JDBC编程步骤如下 1 Load the Driver 加载驱动 1 注冊驱动有三种方式 1 Class forName com mysql jdbc Driver 推荐这样的方式 不会对详细的驱动类产生依赖 2 DriverManage
  • 菜鸟学习篇--Vuecli4.0 Vant ui组件样式无效果

    新建了个vue项目 按需引入vant组件的时候 发现页面不出样式效果 解决办法是 第一步 在bable config js文件中加入 plugins import libraryName vant libraryDirectory es s
  • git需要掌握的基础知识

    Git的简介 Git 是一款免费的 开源的 分布式的版本控制系统 旨在快速高效地处理无论规模大小的任何软件工程 每一个 Git克隆 都是一个完整的文件库 含有全部历史记录和修订追踪能力 不依赖于网络连接或中心服务器 其最大特色就是 分支 及
  • 7 个隐藏的 Blender 技巧将改善您的工作流程

    谁不喜欢秘密技巧 因为 Blender 是一个全面的 多功能的工具 所以有很多隐藏的复活节彩蛋 隐藏在可见表面之下的时尚工具和功能 对于今天的文章中 让我们来找出了最好的秘诀Blender技巧以提高您的工作流程与效率 1 轻松选择集合中的所
  • Spring + MyBatis

    MyBatis ORM 对象 关系映射 完成对象数据到关系型数据映射的机制称为对象 关系映射 1 MyBatis是一个ORM框架 也是一个持久层框架 MyBatis封装了JDBC 将数据库中的表数据自动封装到对象中 这样就可以以面向对象的方
  • 快手小店怎么引流?快手怎么做店铺引流?

    短视频的内容丰富 更能吸引广大用户 因为它可以让用户得到视觉的享受等等 就像快手平台 以短视频迅速攻占用户的心 尤其是三四线城市的用户 非常喜欢在快手上分享自己的生活和见闻 现在就连淘宝也想借助快手平台为自己的店铺进行引流 快速实现产品的变
  • IDEA常用插件之注解插件

    文章目录 注解插件 JavaDoc插件 安装 修改配置 生成文档加入自己信息 Easy JavaDoc 安装插件 在线安装 离线安装 中文名自动转英文 加注释 默认快捷键 可通过IDEA快捷键设置修改 注解插件 JavaDoc插件 安装 修
  • 数据库SQL语句期末总复习

    文章目录 SQL的分类 DDL数据定义语言 数据库的定义与撤销 基本表的定义与维护 索引的建立与删除 DQL数据查询语言 单表查询 查询结果排序 分组查询 连接查询 嵌套查询 集合查询 DML数据操作语言 插入数据 更新数据 删除数据 视图
  • 创建HttpPost和HttpGet请求

    1 创建工具类 HttpClient import com alibaba fastjson JSON import org apache http HttpStatus import org apache http client conf
  • react 函数组件父组件调用子组件方法

    react 函数组件父组件调用子组件方法 父组件利用ref对子组件做标记 通过调用子组件方法更改子组件状态 也可以调用子组件方法 首先在父组件中 使用useRef创建一个ref import LogModal from logModal i
  • vue单选框选中_vue radio单选框,获取当前项(每一项)的value值操作

    前言 本文使用了lable关联选中 实际使用中如果不需要 直接将循环语句 v for 写在 input标签上就可以 1 使用v for循环的radio单选框 01 需要注意的是 这是使用的是 change 事件 而不是 click 点击事件
  • NSSCTF刷题

    web NSSCTF 2022 Spring Recruit babyphp
  • UEFI基本概念

    TianoCore UEFI EDK2 UEFI Unified Extensible Firmware Interface 用来取代BIOS TianoCore 一个社区 支持UEFI的开源实现 EDK2 一种UEFI的开发环境 UEFI
  • AI大模型有哪些?国内的

    今年相信大家都被ChatGPT刷过屏 因为它太好用了 问它一个问题 它就能回答 可以帮助我们写各种文字 甚至写代码 对于我们的工作有着很大的帮助 国内这半年对于AI这个行业也出现了很多的公司以及产品概念 各家大厂也在抓紧研发 和GPT一样的
  • 读写锁 share_mutex

    实现一个Windows下的共享锁 读写锁 一 作者 tyc611 cublog cn 2008 11 18 在Windows Vista Server 2008之前 Windows没有提供共享锁 通俗称为读写锁 只能靠自己实现 但从Wind
  • java基础面试题系列(71 - 80)

    20200714 by 1z 请你说明HashMap 和 HashTable的区别 1 是否同步 HashMap是非同步的 HashTable是同步的 2 继承体系 HashTable继承自Dictionary HashMap继承自Abst
  • Linux下多进程通信(signal,pipe)

    操作系统实验导航 实验一 银行家算法 https blog csdn net weixin 46291251 article details 115384510 实验二 多级队列调度和多级反馈队列调度算法 https blog csdn n