天天看点

linux系统中的信号相关知识点概述记录

1、什么是信号

1.1、信号是内容受限的一种异步通信机制

(1)信号的目的:用来通信

(2)信号是异步的(对比硬件中断)

(3)信号本质上是int型数字编号(事先定义好的)

1.2、信号由谁发出

(1)用户在终端按下按键

(2)硬件异常后由操作系统内核发出信号

(3)用户使用kill命令向其他进程发出信号

(4)某种软件条件满足后也会发出信号,如alarm闹钟时间到会产生SIGALRM信号,向一个读端已经关闭的管道write时会产生SIGPIPE信号。

1.3、信号处理方式

(1)忽略信号

(2)捕获信号(信号绑定了一个函数)

(3)默认处理(当前进程没有明显的管这个信号,默认:忽略或终止进程)

2、常见信号介绍

(1)SIGINT                                 2                  Ctrl+C时OS发送给前台进程组中每个进程

(2)SIGABRT                             6                  调用abort函数,进程异常终止

(3)SIGPOLL SIGIO                   8                  指示一个异步IO事件,在高级IO中体积

(4)SIGKILL                                9                  杀死进程的终极方法

(5)SIGSEGV                             11                 无效存储访问时OS发出该信号

(6)SIGPIPE                               13                 涉及管道和socket

(7)SIGALRM                              14                 涉及alarm函数的实现

(8)SIGTERM                              15                 kill命令发送的OS默认终止信号

(9)SIGCHLD                               17                子进程终止或停止时OS向其父进程发送此信号

(10)

SIGUSR1                                         10                 用户自定义信号,作用和意义由应用自己定义

SIGUSR2                                         12

3、进程对信号的处理

3.1、signal函数

3.2、用signal函数处理SIGINT信号

(1)默认处理

(2)忽略处理

(3)捕获处理

细节:

(1)signal函数绑定一个捕获函数后,信号发生后会自动执行绑定的捕获函数,并且把信号编号作为传参传给捕获函数。

(2)signal的返回值在出错时为SIG_ERR,绑定成功时返回旧的捕获函数。

3.3、signal函数的优点和缺点

(1)优点:简单好用,捕获信号常用

(2)缺点:无法简单直接得知之前设置的对信号的处理方法

3.4、sigaction函数介绍

(1)2个都是API,但是sigaction比signal更具有可移植性

(2)用法关键是2个sigaction指针

编程实例:

/*
*功能描述:
*将SIGINT 2	Ctrl+C时OS发送给前台进程组中每个进程,即“CTRL + C”功能重绑定到捕获函数func
*重绑定信号捕获函数func之后,
*当在终端按下“CTRL + C”时,不再执行OS发送给前台进程组中每个进程,即终止当前进程的功能
*而是去执行用户自定义的信号捕获函数func中的内容
*要想结束当前进程,在linux系统中,先使用“ps -ajx”查看当前进程的进程号,记为xxx
*最后,用“kill -9 xxx”结束该进程。
*/


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

// typedef void (*sighandler_t)(int);
	
void func(int sig)
{
	if(SIGINT != sig)
	{
		perror("signal");
		return;
	}
	printf("func for signal: %d.\n", sig);
}


int main(void)
{
	// sighandler_t ret = (sighandler_t)-2;

	signal(SIGINT, func);
	//signal(SIGINT, SIG_DFL);	//指定信号SIGINT为默认处理
	//signal(SIGINT, SIG_IGN);	//指定信号SIG_IGN为忽略处理
		
	printf("before while(1)\n");
	
	while(1);
	
	printf("after while(1)\n");
		
	return 0;
}
           

4、alarm和pause函数

4.1、alarm函数

(1)内核以API形式提供的闹钟

4.2、pause函数

(1)内核挂起

pause函数的作用就是让当前进程暂停运行,交出CPU给其它进程去执行。当当前进程进入pause状态后,当前进程会表现为“卡住、阻塞住”,要退出pause状态,当前进程需要被信号唤醒。

编程实例:

/*
*功能描述:测试sigaction()、alarm()函数和pause()函数的使用
*1、使用sigaction()函数绑定一个捕获函数func
*2、使用alarm()函数设置一个发送信号的闹钟,发送的信号为SIGALRM			
*3、使用pause()挂起当前进程,当前进程等待alarm信号发生被唤醒执行func函数
*/

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

void func(int sig)
{
	if(SIGALRM == sig)
	{
		printf("alarm happened!\n");
	}
}

int main(void)
{
	unsigned int ret = 0;
	struct sigaction act = {0};
	act.sa_handler = func;
	sigaction(SIGALRM, &act, NULL);
	//signal(SIGALRM, func);
	
	ret = alarm(5);	//5s  设置一个发送信号的闹钟
	printf("1st,ret = %d.\n", ret);
	sleep(3);
	
	ret = alarm(5);	//5s  
	printf("2st,ret = %d.\n", ret);
	sleep(1);
	
	ret = alarm(5);	//5s  
	printf("3st,ret = %d.\n", ret);
	pause();  // 内核挂起当前进程  当前进程等待alarm信号发生被唤醒

	return 0;
}
           

4.3、使用alarm和pause来模拟sleep

编程实例:

/*
*功能描述:使用alarm和pause来模拟sleep
*1、使用sigaction()绑定信号捕获函数func  
*2、使用alarm()函数设置一个发送信号的闹钟,发送的信号为SIGALRM			
*3、使用pause()挂起当前进程,当前进程等待alarm信号发生被唤醒执行func函数
*/

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

void func();	
void mysleep(unsigned int seconds);

int main(void)
{
	printf("before mysleep.\n");
	
	mysleep(3);
	
	printf("after mysleep.\n");
	
	return 0;
}

void func(){}	

void mysleep(unsigned int seconds)
{
	struct sigaction act = {0};
	act.sa_handler = func;
	sigaction(SIGALRM, &act, NULL);		//绑定信号捕获函数func  
	
	alarm(seconds);		//设置alarm函数执行seconds秒
	
	//进程挂起,
	//等待alarm函数执行完毕,产生信号SIGALRM唤醒当前进程,执行捕获信号发生func
	pause(); 
}
           

注:笔记整理记录于——《朱老师物联网大讲堂》—3.5linux中的信号

https://edu.csdn.net/course/play/2405/37602