码迷,mamicode.com
首页 > 系统相关 > 详细

Linux异步signal

时间:2015-08-04 17:18:32      阅读:211      评论:0      收藏:0      [点我收藏+]

标签:signal   信号   linux   unix   

       信号的本质是异步。异步一这个词,听着高端大气上档次,又让人云山雾绕,其则不然。其实我们想想,我们这个世界是异步的,每个人干事儿,并不总是A->B->C->D这种。比如我在网上买了东西,我其实并不知道快递几时能到。我可能在公司里面,在喝水,在回邮件,在查bug,在写代码,突然收到了快递小哥的电话,注意这就是信号的delivery。由于快递的到来,我不得不停下我手头的活儿,去签收快递。这就是传说中的典型的异步。我不知道快递小哥几时给我电话,但是我收到电话就去签收,这是我的信号处理函数。更高级一点,如果我在参加重要的会议,我可能需要屏蔽快递小哥的电话(假如我知道其电话),这已经是linux下信号的高级应用(sigprocmask)了。

       信号是一种机制,是在软件层次对中断机制的一种模拟,内核让某进程意识到某特殊事情发生了。强迫进程去执行相应的信号处理函数。至于信号的来源可能来自硬件如按下键盘或者硬件故障(如ctrl+c发送SIGINT),可能来自其他进程(kill,sigqueue),可能来自自己进程(raise)。

信号的产生:

1,当用户按下某些按键时,产生信号.

2,硬件异常产生信号:除数为 0 ,无效的存储访问等等.这些情况通常由硬件检测到,将其通知内核,然后内核产生适当的信号通知进程,例如,内核对正访问一个无效存储区的进程产生一个 SIGSEGV 信号.

3,进程用 kill 函数 将信号发送给另一个进程.

4,用户可用 kill 命令将信号发送给其他进程.


信号类型 
信号的名字是由所包含的头文件signal.h来定义的。他们以"SIG"开头,如下所示:

信号名 描述

SIGABORT 处理失败

SIGALRM 报警时钟

SIGFPE 浮点异常

SIGHUP 挂起

SIGILL 非法指令

SIGINT 终端中断

SIGKILL Kill(不能被捕获或是忽略)

SIGPIPE 写入没有读端的管道

SIGQUIT 终端退出

SIGSEGV 非法的内存段访问

SIGTERM 终止

SIGUSR1 用户定义的信号1

SIGUSR2 用户定义的信号2

SIGHUP :从终端上发出的结束信号.

SIGINT :来自键盘的中断信号 ( ctrl + c ) .

SIGKILL :该信号结束接收信号的进程 .

SIGTERM:kill 命令发出 的信号.

SIGCHLD:标识子进程停止或结束的信号.

SIGSTOP:来自键盘 ( ctrl + z ) 或调试程序的停止执行信号.


信号处理
       当某信号出现时,将按照下列三种方式中的一种进行处理.

1,忽略此信号:大多数信号都按照这种方式进行处理,但有两种信号却决不能被忽略.它们是:SIGKILL 和 SIGSTOP . 这两        种信号不能被忽略的原因是:它们向超级用户提供了一种终止或停止进程的方法.

2,执行用户希望的动作:通知内核在某种信号发生时,调用一个用户函数,在用户函数中,执行用户希望的处理.

3,执行系统默认动作:对大多数信号的系统默认动作是终止该进程.

        当系统捕捉到某个信号时,可以忽略该信号或是使用指定的处理函数来处理该信号,或者使用系统默认的方式。
        信号处理的主要方法有两种,一种是使用简单的 signal 函数,另一个是使用信号集函数.


signal函数
#include <signal.h>
void (*signal(int sig, <strong>void (*func)(int)</strong>))(int);
       这个复杂的声明signal是一个需要两个参数的函数,sig与func。要捕获或是忽略的信号是由sig参数来指定的。当接收到指定的信号时要调用的函数是由func来指定的。这个函数必须是带有一个int作为参数(接收到的信号),并且其类型为void。而这个signal()函数的返回值也为一个函数指针,这个函数指针指向一个带一个整型参数,并且返回值为void的一个函数信号函数本身返回一个相同类型的函数,这是函数设置的要处理的信号标识号,或是下面两个特殊值中的一个,这俩宏也可以作为信号处理函数。

SIG_IGN 忽略这个信号

SIG_DFL 重新载入默认

pause 函数 

#include <signal.h>
int pause ( void ):

pause 函数使调用进程挂起直至捕捉到一个信号。


例子1:

 #include <signal.h>  
 #include <stdio.h>  
 #include <unistd.h>  
      
void ouch(int sig)  
{  
	printf("I got signal %d\n", sig);  
	(void) signal(SIGINT, SIG_DFL);  
//(void) signal(SIGINT, ouch);  
}  
        
int main()  
{  
	(void) signal(SIGINT, ouch);  
   
	while(1)  
	{  
		printf("hello world...\n");  
		sleep(1);  
	}  
 }
 
解析:
        main函数必须解释当我们输入Ctrl+C时所产生的SIGINT信号。在其余时间,他只是无限循环,每一秒输出一条信息。 第一次输入Ctrl+C会使得程序重新响应,然后继续执行。当我们再次输入Ctrl+C时,程序会结束,因为SIGINT的行为已经恢复为默认行为,从而使得程序退出。

例子2:
#include <signal.h>
#include <stdio.h>
#include <unistd.h>

void my_func(int sign_no)
{
	if(sign_no==SIGINT)
		printf("I have get SIGINT\n");
	else if(sign_no==SIGQUIT)
		printf("I have get SIGQUIT\n");
}
int main()
{
	printf("Waiting for signal SIGINT or SIGQUIT \n ");
	
	/*注册信号处理函数*/
	signal(SIGINT, my_func);
	signal(SIGQUIT, my_func);
	
	pause();
	exit(0);
}
解析:
       在终端下将该进程运行起来,然后 进程pause 了,我们再用 kill 给进程发送信号,在另一终端下ps aux 可以找到运行进程的进程号。然后kill -s SIGQUIT +进程号 我们可以在前一个终端下看到 I have get SIGQUIT.


例子3
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
void sig_usr(int sig);

int main(int argc,char *argv[])
{ 
	int i = 0;
  	if(signal(SIGUSR1,sig_usr) == SIG_ERR)
    	printf("Cannot catch SIGUSR1\n");
  if (signal(SIGUSR2,sig_usr) == SIG_ERR)
    printf("Cannot catch SIGUSR2\n");
  while(1) {
    printf("%2d\n", i);
    pause(); 
    /* pause until signal handler
       has processed signal */
    i++;
  }
  return 0;
}

void sig_usr(int sig)
{
  if (sig == SIGUSR1)
    printf("Received SIGUSR1\n");
  else if (sig == SIGUSR2)
    printf("Received SIGUSR2\n");
  else
    printf("Undeclared signal %d\n", sig);
}
解析:
       在终端下将该进程运行起来加上&,然后 进程pause 了,我们再用 kill 给进程发送信号,在另一终端下,kill -SIGUSR1 +进程号。我们可以在前一个终端下看到Received SIGUSR1。kill -SIGABRT +进程号,则退出。




版权声明:本文为博主原创文章,未经博主允许不得转载。

Linux异步signal

标签:signal   信号   linux   unix   

原文地址:http://blog.csdn.net/tfygg/article/details/47277729

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!