并发基础知识(二)[进程间通信·信号]

2023-11-09

1.信号   


    信号是进程间通信的一种方式,这种方式没有数据传输。
    只是在内核中传递一个信号(整数),信号的表示是一个整数。
    不同的信号值,代表不同的含义,当然用户可以自定义信号。
    那么自定义的信号的含义和值由程序员来定和解释
    
                                Term:Terminate 中止
        signal          value        Action        Comment
    --------------------------------------------------------------------------
        SIGHUP        1       Term    Hangup detected on controlling terminal
                                        or death of controlling process
                                        控制终端的挂起操作,或者是控制进程死亡时, 
                                        控制终端上的所有进程都会收到 SIGHUP 信号
                                        
                                        
        SIGINT        2       Term    Interrupt from keyboard
                                      从键盘上收到的中断信号, ctrl + C      
        SIGQUIT       3       Core    Quit from keyboard
                                        CTRL + Z 
        
        SIGILL        4       Core    Illegal Instruction
                                        非法指令
        SIGABRT       6       Core    Abort signal from abort(3)
                                        调用abort这个函数时,进程会收到
                                        SIGABRT这个信号
        SIGFPE        8       Core    Floating-point exception
                                        浮点运算异常的时候,产生SIGFPE信号
        
        SIGKILL       9       Term    Kill signal 任何进程只要收到这两个信号就必死无疑
        SIGSTOP   17,19,23    Stop    Stop process 而且不能捕获的                                    
        
        SIGSEGV      11       Core    Invalid memory reference
                                        非法内存引用时,会收到SIGSEGV信号
                                        =》segamation Fault 
                                        
        SIGPIPE      13       Term    Broken pipe: write to pipe with no
                                        readers; see pipe(7)
                                       当你往一个管道写数据时,没有读端进程时
                                       就会产生SIGPIPE信号。
                                     
        SIGALRM      14       Term    Timer signal from alarm(2)
                                        定时信号,在进程调用alarm时
                                        会在超时的时候,产生SIGALRM信号
        SIGTERM      15       Term    Termination signal
                                        终止信号
        SIGUSR1   30,10,16    Term    User-defined signal 1
        SIGUSR2   31,12,17    Term    User-defined signal 2
                                        用户自定义信号
        SIGCHLD   20,17,18    Ign     Child stopped or terminated
                                        当子进程停止或中止时,父进程会
                                        收到SIGCHLD这个信号
        
        SIGCONT   19,18,25    Cont    Continue if stopped
        SIGTSTP   18,20,24    Stop    Stop typed at terminal
        SIGTTIN   21,21,26    Stop    Terminal input for background process
        SIGTTOU   22,22,27    Stop    Terminal output for background process

    进程在收到一个信号时,通常会有三种处理方式:  
        (1)默认行为
            收到一个信号时,采用操作系统默认的行为。
            大部分信号的默认行为,会把进程给干掉。 
            只有一个SIGCHLD是被忽略的。

        (2)捕捉信号
            把一个信号 与  用户自定义的信号处理函数关联起来。
            那么在收到该信号时,就会自行调用该处理函数。
            

        (3)忽略该信号 

        
2.信号处理过程         


    通过"软件中断/软中断"来实现的,

    你的信号处理函数其实是在 中断上下文 执行,
        信号处理函数  -》 “软中断函数”
        
        //信号处理函数 是 线程安全的/可重入
        
        进程上下文:进程的大环境下,“时间片轮转”
            一个进程的执行状态又分为: 
                用户态:在执行用户自己的代码
                内核态:进入操作系统内核执行的
        中断上下文:就是中断的环境下。“中断模式” 
                中断处理 
                
                interrupt 

当一个进程接收到信号时,操作系统会对该进程进行处理和调度。以下是信号处理的一般过程:

信号传递:当进程接收到信号时,操作系统会将信号传递给进程。这是通过向进程发送一个特定的软中断(software interrupt)或触发硬件中断(hardware interrupt)来实现的。

信号处理函数调用:接收到信号的进程会根据之前对信号进行的处理注册,执行与该信号关联的信号处理函数。每个信号都有一个默认的处理行为,但进程可以选择为特定信号注册自己的信号处理函数。

信号处理:当操作系统调用信号处理函数时,进程会执行与信号关联的操作。这可能包括异常处理、资源回收、状态更新等操作。在处理完信号后,进程可以恢复执行原来的程序。

需要注意的是,操作系统对接收到信号的进程的调度方式可能会根据不同的操作系统和调度策略而有所不同。一般来说,操作系统可能会采用以下方式处理接收到信号的进程:

抢占式调度:操作系统会立即中断当前进程的执行,将控制权转移到信号处理函数。这种方式会立即响应信号,但可能会导致进程的执行中断。

非抢占式调度:操作系统会等待进程主动释放CPU控制权后,再调用信号处理函数。这种方式会等待进程处于合适的执行点,然后才会响应信号。

对于实时操作系统(Real-Time Operating System),会有更灵活的机制来处理信号和调度进程,以满足实时性的要求。

综上所述,当一个进程接收到信号时,操作系统会将信号传递给进程,并根据调度策略执行相应的信号处理函数。具体的调度方式可能会因操作系统和调度策略而有所不同      


3.linux下信号相关的API函数


    1.发送信号  


        1.kill函数 


        头文件 
            #include <sys/types.h>
            #include <signal.h>
        函数功能 
            用来把一个信号发送到一个指定的进程或多个进程
        函数原型
            int kill(pid_t pid, int sig);
        函数参数 
            pid_t pid        //指定信号的接收者(可能是多个进程)
                                pid > 0:pid表示接收者进程 
                                pid = 0:发送信号给调用进程同组的所有进程
                                pid = -1:发送信号给所有进程(有权限发送的所有)
                                pid < -1:发送信号给组id等于 pid绝对值的所有进程
            int sig            //要发送的信号的信号值                    
            
            
        函数返回值
            成功: (至少有一个进程成功接收到信号)返回0
            失败: 返回-1,同时errno被设置 
        练习:  
            1.写一个程序,发送一个SIGKILL 给某一个进程或多个进程
                
    -------------------------------------------------------------


    2.raise:发送信号给自己  


        头文件 
            #include <signal.h>
        函数功能 
            发送一个信号给调用者进程
        函数原型
            int raise(int sig);
        函数参数  
            int sig  //要发送的信号 
        函数返回值 
            成功:返回0
            失败:返回非0
        
            《=》 kill(getpid(),sig);
    ---------------------------------------------------------------


    3.alarm发送一个闹钟信号  


        头文件 
            #include <unistd.h>
        函数功能
            定时发送一个闹钟信号(SIGALRM)给本进程。
            "闹钟":每个进程都有属于自己的一个“闹钟”
            “闹钟”时间到了,进程就会收到SIGALRM的信号,
            但是同一时刻一个进程只有一个“闹钟”生效
        函数原型
            unsigned int alarm(unsigned int seconds);
        函数参数 
            unsigned int seconds        //多少秒后,发送一个“闹钟信号”
                                        0,cancal a alarm 取消一个闹钟
        函数返回值 
            返回上一个闹钟的剩余秒数
            
            例子:  
                alarm(5);
                int r = alarm(10);//10秒后会收到一个"闹钟信号"
                                    //前面的那个闹钟将替换了。 
                ...
                alarm(0);  //取消闹钟     
    --------------------------------------------------
        大部分信号的默认行为,是把收到信号的进程kill掉。
        那么我们能不能改变这个默认行为呢?
            改变信号的处理方式 --》 捕捉信号
            


    (2)捕捉信号:改变信号的处理方式 


        使用这个函数 需要在头文件前面添加#define __GNU__SOURCE 这个宏定义 
        头文件
            #include <signal.h>
        函数功能
            捕捉和改变信号的处理方式
        函数原型
                typedef void (*sighandler_t)(int);
            sighandler_t signal(int signum, sighandler_t handler);
        函数参数
            int signum                //要捕捉的那个信号的信号值
            sighandler_t handler    //sighandler_t是一个函数指针的类型
                                        它可以用来定义函数指针变量。 
                                        信号的处理方式
                                        (1)SIG_IGN:忽略该信号
                                        (2)SIG_DFL:default,采用操作系统默认的处理方式
                                        (3) 自定义的处理函数  
                                            无返回值,但是带一个int的参数(用来保存收到的那个信号的信号值)
                                            void my_sig_handler(int sig)
                                            {
                                            
                                            }
                
        函数返回值
            成功: 返回 用户改变的信号处理方式的上一次的处理方式,就是指向那个处理函数 ,当我们通过 
                    这个函数指针调用那个函数就可以看到上一次的处理方式,如果没有上一次,则指向NULL
            失败: 返回SIG_ERR,同时errno被设置
        
        练习: 
            我们的程序,通常可以被键盘的CTRL + C 干掉,
            请写一个程序,CTRL + C 干不掉你了?
        


    (3)    等待信号到来   


        pause:让进程停在那里,等待某个信号的到来。
            直到收到信号。
            
        头文件 
            #include <unistd.h>
        函数功能 
            让进程停在那里,等待某个信号的到来。直到收到信号。
        函数原型
             int pause(void);
        函数参数 
            无
        函数返回值 
            只在捕捉到信号时返回。返回-1,errno被设置为EINTR。

#include <stdio.h>
#include <sys/types.h>
#include <signal.h>


int main(int argc, char * argv [ ])
{

	int k = kill(2647, 19);    //指定进程发送信号
	if(k == -1)
	{
		perror("kill send failed\n");
	}
	/*k = kill(2853, 3);
	if(k == -1)
	{
		perror("kill send failed\n");
	}*/

	return 0;
}
#include <stdio.h>
#include <signal.h>
int main(int argc, char * argv [ ])
{
	int r = raise(9);
	if(r != 0)
	{
		printf("raise failed\n");
	}
	while(1);

	return 0;
}
#include <stdio.h>
#include <unistd.h>
int main(int argc, char * argv [ ])
{
	int r = alarm(5);
	printf("r =%d\n",r);
	r = alarm(2);
	printf("r = %d\n",r);
	r = alarm(0);
	printf("r = %d\n",r);
	while(1);


	return 0;
}
#define  _GNU_SOURCE
#include <stdio.h>
#include <signal.h>
#include <unistd.h>

//信号的新的处理方式
void signal_handler(int sig)
{	
	if(sig == 1)
	{
		printf("test last\n");
	}
	if(sig == 2)
	{
		printf("kill buliao I\n");
	}


}


void signal_handlerxx(int sig)
{
	if(sig == 2)
	{
		printf("you kill buliao I\n");
	}
}

int main(int argc, char * argv [ ])
{
	sighandler_t p = signal(SIGINT, signal_handler);  //信号捕获
	if(p == SIG_ERR)
	{
		perror("signal failed\n");
	}
	if(p == NULL)
	{
		printf("no last\n");
	}
	
	p = signal(SIGINT, signal_handlerxx);  //信号捕获
	if(p == SIG_ERR)
	{
		perror("signal failed\n");
	}
	if(p == NULL)
	{
		printf("no last\n");
	}
	else
	{
		p(1);  //===》signal_handler(1);
		
	}
	
	int s = pause();
	if(s == -1)
	{
		perror("");
	}
	printf("qqqqqqqqqqqq\n");

	
	while(1);
	return 0;
}
#include <stdio.h>
int main(int argc, char * argv [ ])
{

	while(1);
	return 0;
}

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

并发基础知识(二)[进程间通信·信号] 的相关文章

随机推荐

  • Git合并不同url的项目

    本文由云 社区发表 作者 工程师小熊 摘要 为了让项目能实现Git Gerrit Jenkin的持续集成 我们把项目从Git上迁移到了Gerrit上 发现有的同事在老Git提交代码 因为Gerrit做了同步 在Gerrit上有新提交的时候就
  • json文件格式详解

    json文件格式详解 JSON JavaScript Object Notation 是一种轻量级的数据交换格式 易于人阅读和编写 同时也易于机器解析和生成 它基于JavaScript Programming Language Standa
  • Latex排列图片:自由定义N行M列的排列方式

    首先导包 usepackage graphicx usepackage float usepackage subfigure 图片排成一行 begin figure htbp centering subfigure 图1 begin min
  • 【解决weditor报错】Local server not started, start with

    前言 大家在使用weditor查找元素的时候 经常会遇到 Local server not started start with 这个错误 下面是我个人的一些解决方法 供大家参考 原因1 浏览器问题导致 浏览器的原因导致的界面未刷新 我的就
  • 解决从GitHub下载文件时缓慢的问题

    我们知道 访问GitHub在国内的速度还算过得去 但是从GitHub上下载文件的速度就非常慢了 以下方法就是为了解决下载速度缓慢的 截止2019 9 5前测试有效 1 用记事本打开hosts文件 路径为C Windows System32
  • Mysql 实践(一):部署和安装

    1 目标 卸载centos自带的mysql 安装mysql 5 6 33 2 步骤 1 下载mysql 下载地址 http dev mysql com downloads mysql 5 6 html downloads 我们下载 这些包
  • 基于SSM框架的实验室开放管理系统

    系统功能结构设计 在分析并得出使用者对程序的功能要求时 就可以进行程序设计了 管理员功能结构图 管理员主要负责填充图书和其类别信息 并对已填充的数据进行维护 包括修改与删除 管理员也需要审核老师注册信息 发布公告信息 管理自助租房信息等 用
  • flutter初学之悬浮按钮

    期望 想实现一个悬浮在整个页面的悬浮按钮 实现1 用FloatingActionButton实现 新增悬浮按钮 Widget createFixedAddWidget ProductEntryState state Dispatch dis
  • linux环境下查看因内存占用过大被杀掉的进程

    文章目录 前言 查询方法 通过系统日志查找 通过dmesg命令查找 进程被杀的原因 总结 前言 最近发生两次游戏服务器进程突然消失的事件 查询日志上下文没有找到有用的信息 日志显示运行到某处戛然而止 此处代码逻辑简单 排除异常逻辑导致的服务
  • data_support/utlist(关于编译器的一些宏宏设置)

    ifndef UTLIST H tlist 权限查看程序 define UTLIST H define UTLIST VERSION 1 9 8 include
  • 灰度图像直方图均衡化公式及实现

    图像的直方图 直方图是图像中像素强度分布的图形表达方式 它统计了每一个强度值所具有的像素个数 直方图均衡化 是通过拉伸像素强度分布范围来增强图像对比度的一种方法 是图像处理领域中利用图像直方图对对比度进行调整的方法 均衡化指的是把一个分布
  • 华为手机发展史

    一 成立手机业务部 大家好 我是小码哥 今天我们来聊一下华为手机的发展史 作为国内乃至世界技术成熟大型互联网企业 已经成为国内市场不可缺失的一部分 华为由任正非在1987年创办的 至今已有34年 华为最初是做交换机起家 随着互联网的发展 华
  • 对象数组(初学)

    目录 一 什么是对象数组 二 定义对象数组 三 对象数组初始化 四 访问对象数组元素 五 new和对象数组 一 什么是对象数组 所谓对象数组 指每一个数组元素都是对象的数组 即若一个类有若干个对象 把这一系列的对象用一个数组来存放 对象数组
  • 关闭httpclient4.5控制台日志输出

    httpclient4 5每次执行的时候都会在控制台输出大量日志 一般情况下并不需要 去官方看了 没找到去掉日志的方法 囧 官网链接 https hc apache org httpcomponents client 4 5 x loggi
  • 2020-09-07

    使 mqtt fx连阿 云时 直提 MQTTException 最近在搞一个Mqtt项目 在用mqtt fx工具做测试时怎么都连接不上阿里云 直提 MQTTException 记得之前也都是可能的 操作好像都是按照官方的文档来操作的 密码也
  • RX8025T RTC读写与秒中断

    目录 一 精度 二 读写时序 三 写RTC对其内部ms计数的影响 四 在FPGA中用GPS校正RTC 五 ms维护 六 IIC防锁死计数清零 七 日期计算星期公式 一 精度 二 读写时序 接口为IIC 读写时序如下图 注意 1 写操作 写从
  • PHP常见问题总结

    1 为什么会出现这种情况 端口什么的都设置正确了 解决方法 请将本机的IIS服务关闭 开启Apache服务 IIS服务的关闭方法可参见 https jingyan baidu com article 0f5fb099e0d7216d8334
  • 理解JPEG文件头的格式

    1 JPEG 1 why jpeg jpeg作为图片传输格式使用最为普遍 压缩比最高 每天我们都会产出和传输大量的jpeg格式数据 手机拍出来的格式默认是jpeg 朋友圈各种分享 磁盘上积累了大量的jpeg 因此本人一直对jpeg头部数据非
  • CLIP:创建图像分类器

    介绍 假设需要对人们是否戴眼镜进行分类 但是没有数据或资源训练自定义模型 在本教程中 你将学习如何使用预训练的CLIP模型创建自定义分类器 无需任何训练 这种方法称为零快照图像分类 它使得能够对在原始CLIP模型训练期间未明确观察到的的类进
  • 并发基础知识(二)[进程间通信·信号]

    1 信号 信号是进程间通信的一种方式 这种方式没有数据传输 只是在内核中传递一个信号 整数 信号的表示是一个整数 不同的信号值 代表不同的含义 当然用户可以自定义信号 那么自定义的信号的含义和值由程序员来定和解释 Term Terminat