Linux中的信号

Posted int data

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux中的信号相关的知识,希望对你有一定的参考价值。

1.什么是信号

(1).信号是内容受限的一种异步通信机制

(2).软中断信号(signal,又简称为信号)用来通知进程发生了异步事件。进程之间可以互相通过系统调用kill发送软中断信号。内核也可以因为内部事件而给进程发送信号,通知进程发生了某个事件。注意,信号只是用来通知某进程发生了什么事件,并不给该进程传递任何数据。 

(3).收 到信号的进程对各种信号有不同的处理方法。处理方法可以分为三类:第一种是类似中断的处理程序,对于需要处理的信号,进程可以指定处理函数,由该函数来处 理。第二种方法是,忽略某个信号,对该信号不做任何处理,就象未发生过一样。第三种方法是,对该信号的处理保留系统的默认值,这种缺省操作,对大部分的信 号的缺省操作是使得进程终止。进程通过系统调用signal来指定进程对某个信号的处理行为。 

2.信号由谁发出

(1)用户在终端按下按键
(2)硬件异常后由操作系统内核发出信号
(3)用户使用kill命令向其他进程发出信号
(4)某种软件条件满足后也会发出信号,如alarm闹钟时间到会产生SIGALARM信号,向一个读端已经关闭的管道write时会产生SIGPIPE信号

3.信号的处理:

信号的处理有三种方法,分别是:忽略、捕捉和默认动作

  • 忽略信号,大多数信号可以使用这个方式来处理,但是有两种信号不能被忽略(分别是 SIGKILLSIGSTOP)。因为他们向内核和超级用户提供了进程终止和停止的可靠方法,如果忽略了,那么这个进程就变成了没人能管理的的进程,显然是内核设计者不希望看到的场景
  • 捕捉信号,需要告诉内核,用户希望如何处理某一种信号,说白了就是写一个信号处理函数,然后将这个函数告诉内核。当该信号产生时,由内核来调用用户自定义的函数,以此来实现某种信号的处理。
  • 系统默认动作,对于每个信号来说,系统都对应由默认的处理动作,当发生了该信号,系统会自动执行。不过,对系统来说,大部分的处理方式都比较粗暴,就是直接杀死该进程。
    具体的信号默认动作可以使用man 7 signal来查看系统的具体定义。

4.常见信号介绍

(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)SIGALARM          14        涉及alarm函数的实现
(8)SIGTERM            15        kill命令发送的OS默认终止信号
(9)SIGCHLD            17        子进程终止或停止时OS向其父进程发此信号
(10)
SIGUSR1                10        用户自定义信号,作用和意义由应用自己定义
SIGUSR2                12
 

5.进程对信号的处理

  • signal函数介绍
  • 用signal函数处理SIGINT信号

(1)默认处理
(2)忽略处理
(3)捕获处理

细节:

(1)signal函数绑定一个捕获函数后信号发生后会自动执行绑定的捕获函数,并且把信号编号作为传参传给捕获函数
(2)signal的返回值在出错时为SIG_ERR,绑定成功时返回旧的捕获函数

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

typedef void (*sighandler_t)(int);


void func(int sig)

	if (SIGINT != sig)
		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为默认处理
	ret = signal(SIGINT, SIG_IGN);		// 指定信号SIGINT为忽略处理
	if (SIG_ERR == ret)
	
		perror("signal:");
		exit(-1);
	
	
	printf("before while(1)\\n");
	while(1);
	printf("after while(1)\\n");
	
	return 0;

signal函数的优点和缺点

(1)优点:简单好用,捕获信号常用
(2)缺点:无法简单直接得知之前设置的对信号的处理方法

sigaction函数介绍

(1)2个都是API,但是sigaction比signal更具有可移植性
(2)用法关键是2个sigaction指针

总结:

sigaction比signal好的一点:sigaction可以一次得到设置新捕获函数和获取旧的捕获函数(其实还可以单独设置新的捕获或者单独只获取旧的捕获函数),而signal函数不能单独获取旧的捕获函数而必须在设置新的捕获函数的同时才获取旧的捕获函数。

6.alarm和pause函数

alarm函数

(1)功能与作用:alarm()函数的主要功能是设置信号传送闹钟,即用来设置信号SIGALRM在经过参数seconds秒数后发送给目前的进程。如果未设置信号SIGALARM的处理函数,那么alarm()默认处理终止进程。

(2)函数返回值:如果在seconds秒内再次调用了alarm函数设置了新的闹钟,则后面定时器的设置将覆盖前面的设置,即之前设置的秒数被新的闹钟时间取代;当参数seconds为0时,之前设置的定时器闹钟将被取消,并将剩下的时间返回。

了解了alarm()函数的功能特性和返回值的特性后,我们就可以对其测试。测试方向有两个:其一,测试常规只单独存在一个闹钟函数alarm()的程序;其二,测试程序中包含多个alarm()闹钟函数。

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

static void sig_alrm(int signo);
int main(void)

  signal(SIGALRM,sig_alrm);
  system("date");
  alarm(20);
  sleep(5);
  printf("%d\\n",alarm(15));
  pause();


static void sig_alrm(int signo)
  system("date");
  return;

pause函数

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

使用alarm和pause来模拟sleep代码:

#include <stdio.h>
#include <unistd.h>			// unix standand
#include <signal.h>



void func(int sig)

	/*
	if (sig == SIGALRM)
	
		printf("alarm happened.\\n");
	
	*/


void mysleep(unsigned int seconds);


int main(void)

	printf("before mysleep.\\n");
	mysleep(3);
	printf("after mysleep.\\n");
	
	
/*	unsigned int ret = -1;
	struct sigaction act = 0;
	
	act.sa_handler = func;
	sigaction(SIGALRM, &act, NULL);
	
	//signal(SIGALRM, func);
	ret = alarm(5);
	printf("1st, ret = %d.\\n", ret);


	sleep(3);
	
	ret = alarm(5);		// 返回值是2但是本次alarm会重新定5s
	printf("2st, ret = %d.\\n", ret);
	sleep(1);
	
	ret = alarm(5);
	printf("3st, ret = %d.\\n", ret);
	
	
	
	
	//while (1);
	pause();		
*/	
	return 0;


void mysleep(unsigned int seconds)

	struct sigaction act = 0;
	
	act.sa_handler = func;
	sigaction(SIGALRM, &act, NULL);
	
	alarm(seconds);
	pause();

linux中的信号怎么理解?

linux的常用信号量BUS与SEGV二者都是错误信号,BUS表示总线错误,SEGV表示段错误,程序崩溃的时候99%都是这两个错误导致的。进程可以捕获和封锁这两类错误。内核对二者的默认处理是memorydumpWINCH窗口改变信号(WINdownCHanged)。例如虚拟终端的行数发生变化时将发送WINCH信号,绝大多数文本编辑器都能捕获WINCH信号自动进行重新配置。内核的默认处理是忽略该信号,并且不进行内存转储。进程可以捕获或者封锁该信号KILL 杀死/删除进程,编号为9STOP 挂起/暂停正在执行的进程,直到收到CONT为止KILLSTOP都不能够被捕获、封锁或者忽略,默认处理都不会产生内存转储。CONT 取消挂起,继续执行进程TSTP 是STOP信号的“软”版本,即在用户输入Ctrl+Z时由终端驱动程序发送的信号。捕获到该信号的进程通常清除它们的状态,如何给自己发送一个STOP信号。TSTP的默认处理不会导致内存转储。INT 中断信号,编号为2当用户输入Ctrl+C时由终端驱动程序发送INT信号INT信号是终止当前操作的请求,简单程序捕获到INT信号时应该退出,拥有命令行或者输入模式的那些程序应该停止他们正在做的事情,清除状态,并等待用户再次输入。TERM 软件终止信号,编号为15TERM是请求彻底终止某项操作的信号,它期望进程清楚自己的状态并退出QUIT 退出信号,编号为3与TERM类似,不同之处在于QUIT信号的默认处理是内存转储,而TERM信号的默认处理没有内存转储。HUP 挂起信号,编号为1,有两种解释:守护进程理解HUP为重新设置的请求,如果守护进程能够不用重新启动就能够重新读取它自己的配置文件并调整自己以适应变化的话,那么HUP信号通常可以用来触发这种行为HUP信号有时有终端驱动程序生成,试图用来清除(也就是终止)跟某个特定终端相连接的那些进程。例如当一个终端会话结束时,或者当一个Modem的连接不经意的断开时,就可能出现这种情况。如果需要某些进程在会话结束之后继续运行,那么在CShell中设法让这些进程变成后台程序,ksh或者bash中可以用nohup来模拟这种行为。++++++++++++++++++++++++++++++++++++++++++++++++++++++++++进程的四种状态runnable(可运行状态)只要有CPU时间,进程就可以执行。一旦进程执行了不能立即完成的系统调用,Linux会把进程转入睡眠状态sleeping(睡眠状态)进程在等待某些事件发生(如终端输入、网络连接)zombie(僵化状态)进程已经执行完毕并试图消亡,但是状态没有收集完stopped(停止状态)进程被挂起,不允许执行。进程收到STOP或者TSTP信号即进入停止状态,可以用CONT信号来重新启动 参考技术A

编号为1 ~ 31的信号为传统UNIX支持的信号,是不可靠信号(非实时的),编号为32 ~ 63的信号是后来扩充的,称做可靠信号(实时信号)。不可靠信号和可靠信号的区别在于前者不支持排队,可能会造成信号丢失,而后者不会。

本回答被提问者采纳

以上是关于Linux中的信号的主要内容,如果未能解决你的问题,请参考以下文章

linux网络编程---------信号大讲堂

Linux网络编程-SIGPIPE信号导致的程序退出问题

(50)LINUX应用编程和网络编程之五 Linux信号(进程间通信)

在linux中网络管理器的接口“org.freedesktop.NetworkManager.Device”上生成的信号名称

linux网络编程中需要注意的信号SIGPIPE

Linux网络子系统之---- PHY 配置