【Linux】进程间通信(1)

news2025/1/12 23:37:35

信号

    什么是信号?信号是给程序提供一种可以处理异步事件的方法,它利用软件中断来实现。不能自定义信号,所有信号都是系统预定义的。

信号由谁产生?

  1. 由shell终端根据当前发生的错误(段错误、非法指令等)Ctrl+c而产生相应的信号

            比如:

            socket通信或者管道通信,如果读端都已经关闭,执行写操作(或者发送数据),

            将导致执行写操作的进程收到SIGPIPE信号(表示管道破裂)

             该信号的默认行为:终止该进程。

                       

     2. 在shell终端,使用kill或killall命令产生信号

常见的信号

       -------------------------------------------

       信号名称                    说明

       -------------------------------------------

       SIGABORT            进程异常终止

       SIGALRM              超时告警

       SIGFPE                 浮点运算异常

       SIGHUP                连接挂断

       SIGILL                   非法指令

       SIGINT                  终端中断  (Ctrl+C将产生该信号)

       SIGKILL                *终止进程                            

       SIGPIPE                向没有读进程的管道写数据

       SIGQUIT                终端退出(Ctrl+\将产生该信号)

       SIGSEGV              无效内存段访问

       SIGTERM              终止

       SIGUSR1              *用户自定义信号1

       SIGUSR2              *用户自定义信号2

       -------------------------------------->以上信号如果不被捕获,则进程接受到后都会终止!

       SIGCHLD             子进程已停止或退出

       SIGCONT            *让暂停的进程继续执行

       SIGSTOP             *停止执行(即“暂停")

       SIGTSTP              中断挂起

       SIGTTIN              后台进程尝试读操作

       SIGTTOU             后台进程尝试写

       -------------------------------------------

信号的处理

1. 忽略此信号

2. 捕捉信号,指定信号处理函数进行处理

3. 执行系统默认动作,大多数都是终止进程

 信号的捕获

 信号的捕获,是指,指定接受到某种信号后,去执行指定的函数。

 注意:SIGKILL和SIGSTOP不能被捕获,即,这两种信号的响应动作不能被改变。

 Example1:

main函数中,signal函数中存放指定的信号编号和函数指针,当捕获到该信号时,将执行函数指针所指向的函数。
由于该函数改变了收到SIGINT信号(即ctrl + c)的行为(即原来的结束进程),故当程序启动时,再次按下ctrl + c,进程不会结束,而是执行myhandle函数。

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>


void myhandle(int sig) 
{
	printf("Catch a signal : %d\n", sig);
}

int main(void) 
{

	signal(SIGINT, myhandle);
	while (1) {
            sleep(1);
	}
	return 0;
}

 signal函数的具体含义如下图所示。

 Example2:

在Example1的基础上,在myhandle()函数中添加了一句
signal(SIGINT,SIG_DFL);
该段程序在首次捕捉到SIGINT信号后,不会结束进程,而是进入myhandle(),执行相关操作,在myhandle()中,又重新将捕获到SIGINT信号后的操作恢复默认,即结束进程。

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

void myhandle(int sig) 
{
	static int cnt = 0;
	printf("Catch a signal : %d\n", sig);

	signal(SIGINT, SIG_DFL); //等同于signal(sig, SIG_DFL);
}

int main(void) 
{
	signal(SIGINT, myhandle);

	while (1) {
        sleep(1);
	}

	return 0;
}

使用sigaction  (项目实战强烈推荐使用

       sigaction与signal的区别: sigaction比signal更“健壮”,建议使用sigaction

           

       用法:man 2 sigaction

      

       结构:struct sigaction

        struct sigaction {

            void (*sa_handler)(int);     /* 信号的响应函数 */

            sigset_t   sa_mask;          /* 屏蔽信号集 */                        

            int sa_flags;                     /* 当sa_flags中包含 SA_RESETHAND时,接受到该信号并调用指定的信号处理函数执行之后,把该信号的响应行为重置为默认行为SIG_DFL */

            ...

        }

       

        补充:

        当sa_mask包含某个信号A时,则在信号处理函数执行期间,如果发生了该信号A,

         则阻塞该信号A(即暂时不响应该信号),直到信号处理函数执行结束。

         即,信号处理函数执行完之后,再响应该信号A

Example3:

其中sigemptyset()函数是用于清空屏蔽信号集的掩码,相当于初始化的作用。
若在该函数中,将sa_flags设为SA_RESETHAND则与Example2的功能类似,捕捉相应信号对应的函数只执行一次,往后遍恢复默认设置。

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

void myhandle(int sig) 
{
	printf("Catch a signal : %d\n", sig);
}

int main(void) 
{
	struct sigaction act;

	act.sa_handler = myhandle;
	sigemptyset(&act.sa_mask);
    act.sa_flags = 0;

	sigaction(SIGINT, &act, 0);

	while (1) {
        
	}

	return 0;
}

信号的发送

       信号的发送方式:

             在shell终端用快捷键产生信号

             使用kill,killall命令。

             使用kill函数和alarm函数

使用kill函数

           给指定的进程发送指定信号

           用法:man 2 kill

           注意:

                        给指定的进程发送信号需要“权限”:

                        普通用户的进程只能给该用户的其他进程发送信号

                        root用户可以给所有用户的进程发送信号

           kill失败

               失败时返回-1

               失败原因:

                     权限不够

                     信号不存在

                     指定的进程不存在

 Example4:

创建一个子进程,子进程每秒中输出字符串“child process work!",父进程等待用户输入,如果用户按下字符A, 则向子进程发信号SIGUSR1, 子进程的输出字符串改为大写; 如果用户按下字符a, 则向子进程发信号SIGUSR2, 子进程的输出字符串改为小写 

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

int workflag = 0;

void work_up_handle(int sig) 
{
	workflag = 1;
}

void work_down_handle(int sig) 
{
	workflag = 0;
}



int main(void) 
{
	pid_t pd;
	char c;


	pd = fork();
	if (pd == -1) {                  //子线程创建失败
		printf("fork error!\n");
		exit(1); 
	} else if (pd == 0) {            //子线程创建成功,子线程执行如下程序
		char *msg;
		struct sigaction act; 
		act.sa_flags = 0;
		act.sa_handler = work_up_handle;
		sigemptyset(&act.sa_mask);		
		sigaction(SIGUSR1, &act, 0);    //SIGUSR1信号与work_up_handle函数挂钩
		
		act.sa_handler = work_down_handle;
		sigaction(SIGUSR2, &act, 0);    //SIGUSR2信号与work_down_handle函数挂钩
		
		while (1) {
			if (!workflag) {
				msg = "child process work!";
			} else {
				msg = "CHILD PROCESS WORK!";
			}
			printf("%s\n", msg);
			sleep(1);
		}
		
	} else {                          //父进程执行如下程序
		while(1) { 
			c = getchar();            
			if (c == 'A') {          //若输入的是‘A’,则产生SIGUSR1信号
				kill(pd, SIGUSR1);
			} else if (c == 'a') {   //若输入的是‘a’,则产生SIGUSR2信号
				kill(pd, SIGUSR2);
			}
		}
	}
	

	return 0;
}

Example5:

创建一个子进程,子进程在5秒钟之后给父进程发送一个SIGALR,父进程收到SIGALRM信号之后,“闹铃”(用打印模拟)

getppid():获取父进程编号。
pause():把该进程挂起,并阻塞,直到收到任意一个信号,才继续往下执行。 

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

int wakeflag = 0;

void wake_handle(int sig) 
{
	wakeflag = 1;
}

int main(void) 
{
	pid_t pd;
	char c;


	pd = fork();
	if (pd == -1) {
		printf("fork error!\n");
		exit(1);
	} else if (pd == 0) {
		sleep(5);
		kill(getppid(), SIGALRM);  //getppid() 获得父进程编号
                                             //向父进程发送SIGALRM信号
	} else {
		struct sigaction act; 
		act.sa_handler = wake_handle;  
		act.sa_flags = 0;
		sigemptyset(&act.sa_mask);  //清空掩码

		sigaction(SIGALRM,  &act, 0); //接收到SIGALRM信号后,调用act指定的处理函数  

		pause(); //把该进程挂起,直到收到任意一个信号

		if (wakeflag) {
			printf("Alarm clock work!!!\n");
		}
	}

	return 0;
}

alarm函数

        作用:在指定时间之内给该进程本身发送一个SIGALRM信号。

        用法:man 2 alarm

        注意:时间的单位是“秒”

                 实际闹钟时间比指定的时间要大一点。 

                 如果参数为0,则取消已设置的闹钟。

                 如果闹钟时间还没有到,再次调用alarm,则闹钟将重新定时

                 每个进程最多只能使用一个闹钟。

        

        返回值:

                 失败:返回-1

                 成功:返回上次闹钟的剩余时间(秒)

Example6:给自己的进程发信号 

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <time.h>

int wakeflag = 0;

void wake_handle(int sig) 
{
	wakeflag = 1;
}

int main(void) 
{
	int ret;
	
	struct sigaction act;
	act.sa_flags = 0;
	act.sa_handler = wake_handle;
	sigemptyset(&act.sa_mask);
	sigaction(SIGALRM, &act, 0);
	
	printf("time =%ld\n", time((time_t*)0));

	ret = alarm(5);          //过5s,发送一次alarm信号
	if (ret == -1) {
		printf("alarm error!\n");
		exit(1);
	}

	//挂起当前进程,直到收到任意一个信号
	pause();

	if (wakeflag) {
		printf("wake up, time =%ld\n", time((time_t*)0));
	}

	return 0;
}

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

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

相关文章

商品详情的APP原数据接口测试

一、原数据接口的来源&#xff1a; 原数据接口来源于手机端&#xff0c;随着智能化的发展与普及&#xff0c;越来越多的人都是使用智能手机&#xff0c;这样极大的方便了人民的生活&#xff0c;各大电商平台看准了这个商家&#xff0c;把目光都瞄准这个商机&#xff0c;伴随而…

BP靶场中SQL注入练习

BP靶场中SQL注入练习1.Bp靶场介绍1.1.访问靶场1.2.注意事项2.SQL注入靶场2.1.注意事项2.2.检索隐藏数据2.2.1.开启靶场2.2.2.点击礼物2.2.3.测试类型2.2.4.爆出全部物品(包括隐藏)2.3.登录逻辑2.3.1.开启靶场2.3.2.登录账户2.3.3.注释验证2.3.4.成功登陆2.4.判断列2.4.1.开启靶…

会话技术--cookie和session

一、会话跟踪技术的概述 对于会话跟踪这四个词&#xff0c;我们需要拆开来进行解释&#xff0c;首先要理解什么是会话&#xff0c;然后再去理解什么是会 话跟踪: 会话:用户打开浏览器&#xff0c;访问web服务器的资源&#xff0c;会话建立&#xff0c;直到有一方断开连接&#…

变量、作用域与内存

目录 原始值与引用值 动态属性 复制值 传递参数 确定类型 执行上下文与作用域 作用域链增强 变量声明 1.使用var 的函数作用域声明 2. 使用let 的块级作用域声明 3.使用const 的常量声明 标识符查找 垃圾回收 标记清理&#xff08;最常用&#xff09; 引用计数 内…

2022__我的嵌入式入坑之路

目录 一、学习篇 51单片机&#xff1a; python爬虫&#xff1a; stm32单片机&#xff1a; ad&#xff1a; 立创EDA&#xff1a; openmv&#xff1a; ardunio&#xff1a; ESP32&#xff1a; 汇编语言&#xff1a; ROS&#xff1a; FreeRTOS&#xff1a; matlab&a…

【学习】大数据关键技术

学习内容描述&#xff1a; 大数据涉及的四个环节是什么&#xff1f; 云计算服务的三种服务类型是什么&#xff1f; 重点知识&#xff1a; 大数据涉及的四个环节&#xff1a;1、数据采集&#xff1b;2、数据存储&#xff1b;3、数据管理&#xff1b;4、数据分析与挖掘。云计算…

大型智慧灌区信息化管理系统云平台 智慧灌区信息化管理系统解决方案

平升电子大型智慧灌区信息化管理系统云平台/智慧灌区信息化管理系统解决方案&#xff0c;对灌区的渠道水位、流量、水雨情、土壤墒情、气象等信息进行监测&#xff0c;同时对泵站、闸门进行远程控制&#xff0c;对重点区域进行视频监控&#xff0c;实现了信息的采集、统计、分析…

基于pyautogui的自动识别定位原神风物之诗琴按键弹奏程序

前言&#xff1a;为了学习pyautogui这个库的使用&#xff0c;我准备用它做点东西。比如一个自动弹琴的程序。不过这个琴不是现实里的琴&#xff0c;而是原神里的风物之诗琴。&#xff08;这里有个网页版模拟器可以试试&#xff1a;风物之诗琴模拟器 (haveyouwantto.github.io)&…

Spring 监听器listener原理

1.创建本地事件和事件监听器/*** 事件类*/ public class MyEventA extends ApplicationEvent {private static final long serialVersionUID 1L;public MyEventA(Object source) {super(source);System.out.println("MyEventA 构造方法被执行了...");}public void o…

基于matlab开发的车牌检测与字符分割项目附源码

文章目录1 任务概述项目完整matlab源码2 基本流程2.1 车牌定位2.1.1 图像预处理2.1.2 边缘检测2.1.3 形态学操作2.1.4 重操作判断2.1.5 区域选择2.1.6 倾斜校正2.1.7 精确选择2.2 字符分割2.3 字符识别3 结果分析3.1 车牌定位3.2 字符分割3.3 字符识别4 总结5 参考资料1 任务概…

安装vim的最新版本

1、通过源码安装 对于Linux系统&#xff0c;可以通过源码编译来安装最新版本&#xff0c;我在wsl ubuntu下的操作如下&#xff1a; 获取vim的源码&#xff1a; git clone https://github.com/vim/vim.git刚开始我帆了墙&#xff0c;结果下载不动&#xff0c;关了帆墙软件可正常…

【入门AUTOSAR网络管理测试】AUTOSAR网络管理规范需求解读

文章目录前言一、名词解释二、NM报文1.NM报文格式2.NM报文数据场内容三、NM状态机1.NM状态转换图2.状态前言 AUTOSAR Automotive Open System Architecture&#xff0c;汽车开放系统架构&#xff0c;由全球汽车制造商、部件供应商及其他电子、半导体和软件系统公司联合建立&am…

Qt扫盲-QPlainTextEdit理论总结

QPlainTextEdit理论总结一、概述二、用途一&#xff1a;纯文本展示1. 用法2. 只读快捷键三、用途二&#xff1a;纯文本编辑器1. 用法2. 快捷键绑定四、与 QTextEdit 的不同一、概述 QPlainTextEdit是一个只支持纯文本的高级查看器/编辑器。 它经过优化&#xff0c;可以处理大型…

Mac系统下matplotlib中SimHei中文字体缺失报错的解决办法

问题描述import matplotlib.pyplot as plt plt.rcParams[font.sans-serif][SimHei] plt.rcParams[axes.unicode_minus]False使用matplotlib画图时&#xff0c;因为缺少字体&#xff0c;、图像上label上的中文显示时空白小方块。因为matplotlib默认没有中文。解决方法&#xff…

多维时序 | MATLAB实现VMD-SSA-KELM和VMD-KELM变分模态分解结合麻雀算法优化核极限学习机多输入单输出时间序列预测

多维时序 | MATLAB实现VMD-SSA-KELM和VMD-KELM变分模态分解结合麻雀算法优化核极限学习机多输入单输出时间序列预测 目录多维时序 | MATLAB实现VMD-SSA-KELM和VMD-KELM变分模态分解结合麻雀算法优化核极限学习机多输入单输出时间序列预测预测效果基本介绍程序设计学习小结参考资…

城堡、游乐园、地下城!!!500+ 超棒 FBX 模型素材,全部都免费!

近期 Cocos 社区有好几位热心的开发者&#xff0c;整理了一些 CC0 协议 的游戏资源。如果你对 CC0 协议还不太了解&#xff0c;我找到一个中文版的协议说明&#xff0c;看下图&#xff1a;有几点比较重要&#xff1a;作者放弃著作权&#xff0c;已将作品贡献至公共领域可以复制…

【ROS】—— 机器人系统仿真 —RDF、Gazebo与Rviz综合应用(十六)

文章目录前言1. 机器人运动控制以及里程计信息显示1.1 ros_control 简介1.2 运动控制实现流程(Gazebo)1.2.1 为 joint 添加传动装置以及控制器1.2.2 xacro文件集成1.2.3 启动 gazebo并控制机器人运动2. 雷达信息仿真以及显示2.1 新建 Xacro 文件&#xff0c;配置雷达传感器信息…

C++STL之vector的模拟实现

由于vector和string的接口使用方法类似&#xff0c;这里便不再详细讲解vector各种接口的使用了&#xff0c;可以参考之前所发布的string的使用&#xff0c;或者从官方文档中获取详细的使用方法. 目录 vector介绍 构造函数&#xff08;有参&#xff0c;无参&#xff0c;迭代器…

【14】Docker network | bridge | host | none | container

目录 1、Docker 运行的基本流程为: 2、Docker0 3、Docker默认的三种网络模式 4、Docker的网络命令 5、网络模式 6、实例&#xff1a; 7、bridge模式 8、host模式 9、none模式 10、container模式 11、自定义网络 1、Docker 运行的基本流程为: 1.用户是使用 Docker Clie…

UDS诊断系列介绍10-28服务

本文框架1. 系列介绍1.1 28服务概述2. 28服务请求与应答2.1 28服务请求2.2 28服务正响应2.3 否定应答3. Autosar系列文章快速链接1. 系列介绍 UDS&#xff08;Unified Diagnostic Services&#xff09;协议&#xff0c;即统一的诊断服务&#xff0c;是面向整车所有ECU的一种诊…