Linux异步------signal

news/2024/5/19 0:56:26 标签: 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 非法指令

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

SIGPIPE 写入没有读端的管道

SIGQUIT 终端退出(ctrl+/)

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 signo, handler hander);
参数:
signo--信号名字
hander有三种选择:1、SIG_IGN 忽略信号 2、SIG_DFL 执行默认动作 3、 捕捉信号后调用的函数地址(回调函数) 
例如:typedef void (*handler)(int)

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 +进程号,则退出。





http://www.niftyadmin.cn/n/1568685.html

相关文章

Linux ipc------System V消息队列

消息队列就是一个消息的链表。可以把消息看作一个记录&#xff0c;具有特定的格式以及特定的优先级。对消息队列有写权限的进程可以向其中按照一定的规则添加新消息&#xff1b;对消息队列有读权限的进程则可以从消息队列中读走消息。 消息队列和共享内存类似消息队列它允许一…

Linux ipc------System V概述

System V IPC指的是AT&T在System V.2发行版中引入的三种进程间通信工具: (1)信号量&#xff0c;用来管理对共享资源的访问; (2)共享内存&#xff0c;用来高效地实现进程间的数据共享; (3)消息队列&#xff0c;用来实现进程间数据的传递。 我们把这三种工具统称为System VIP…

linux线程介绍

一、什么是线程&#xff1f; 线程是进程的一个实体&#xff0c;是CPU调度和分派的基本单位&#xff0c;它是比进程更小的能独立运行的基本单位。线程自己基本上不拥有系统资源&#xff0c;只拥有一点在运行中必不可少的资源(如程序计数器&#xff0c;一组寄存器和栈)&#xff0…

Linux线程同步概述

对于多线程程序来说&#xff0c;同步(synchronization)是指在一定的时间内只允许某一个线程访问某个资源 。而在此时间内&#xff0c;不允许其它的线程访问该资源。我们可以通过互斥锁(mutex)&#xff0c;条件变量(condition variable)和读写锁(reader-writer lock)来同步资源。…

Linux异步-----信号量集

在实际的应用中一个应用程序需要对多个信号进行处理&#xff0c;为了方便&#xff0c;linux系统引进了信号集的概念。信号集用多个信号组成的数据类型sigset_t.可用以下的系统调用设置信号集中所包含的数据。 1、sigset_t在/include/asm-generic/signal.h中定义。 typedef st…

C与C++语法总结

【C编程思想&#xff1a;数据结构算法】 C语言包含内容繁多&#xff0c;在这里做了一个归纳总结。分为6个部分&#xff1a; 数据类型 存储类型 基本要素 预处理 函数 文件操作 一、基本要素 1、常量 &#xff08;1&#xff09;数字常量 &#xff08;2&#xff09;字符常量 普通…

排序法总结与比较

排序&#xff1a;对一序列对象根据某个关键字进行排序&#xff1b; 稳定&#xff1a;如果a原本在b前面&#xff0c;而ab&#xff0c;排序之后a仍然在b的前面&#xff1b; 例如&#xff1a;插入排序、冒泡排序、归并排序、计数排序、基数排序、桶排序 不稳定&#xff1a;如果a原…

一个例子说明虚函数

一、虚函数的基础知识 虚函数的定义&#xff0c;调用&#xff08;外部函数的指针或引用&#xff0c;成员函数&#xff09;&#xff0c;构造函数和析构函数中调用虚函数&#xff0c;虚析构函数 赋值兼容&#xff0c;构造函数的重载&#xff0c;构造函数的初始化列表 见代码&…