00. 目录

文章目录

  • 00. 目录
  • 01. 信号概述
  • 02. 信号编号
  • 03. 信号产生方式
  • 04. kill发送信号
  • 05. pause等待信号
  • 06. 信号处理方式
  • 07. 信号处理函数
  • 08. 附录

01. 信号概述

信号Linux 进程间通信的最古老的方式。信号是软件中断,它是在软件层次上对中断机制的一种模拟,是一种异步通信的方式 。信号可以导致一个正在运行的进程被另一个正在运行的异步进程中断,转而处理某一个突发事件。

“中断”在我们生活中经常遇到,譬如,我正在房间里打游戏,突然送快递的来了,把正在玩游戏的我给“中断”了,我去签收快递( 处理中断 ),处理完成后,再继续玩我的游戏。这里我们学习的“信号”就是属于这么一种“中断”。我们在终端上敲“Ctrl+c”,就产生一个“中断”,相当于产生一个信号,接着就会处理这么一个“中断任务”(默认的处理方式为中断当前进程)。

信号可以直接进行用户空间进程和内核空间进程的交互,内核进程可以利用它来通知用户空间进程发生了哪些系统事件。

一个完整的信号周期包括三个部分:信号的产生,信号在进程中的注册,信号在进程中的注销,执行信号处理函数。如下图所示:

注意:这里信号的产生,注册,注销时信号的内部机制,而不是信号的函数实现。

02. 信号编号

Linux 可使用命令:kill -l(“l” 为字母),查看相应的信号。

deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$ kill -l1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL       5) SIGTRAP6) SIGABRT      7) SIGBUS       8) SIGFPE       9) SIGKILL     10) SIGUSR1
11) SIGSEGV     12) SIGUSR2     13) SIGPIPE     14) SIGALRM     15) SIGTERM
16) SIGSTKFLT   17) SIGCHLD     18) SIGCONT     19) SIGSTOP     20) SIGTSTP
21) SIGTTIN     22) SIGTTOU     23) SIGURG      24) SIGXCPU     25) SIGXFSZ
26) SIGVTALRM   27) SIGPROF     28) SIGWINCH    29) SIGIO       30) SIGPWR
31) SIGSYS      34) SIGRTMIN    35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3
38) SIGRTMIN+4  39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8
43) SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7
58) SIGRTMAX-6  59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2
63) SIGRTMAX-1  64) SIGRTMAX
deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$

列表中,编号为 1 ~ 31 的信号为传统 UNIX 支持的信号,是不可靠信号(非实时的),编号为 32 ~ 63 的信号是后来扩充的,称做可靠信号(实时信号)。不可靠信号和可靠信号的区别在于前者不支持排队,可能会造成信号丢失,而后者不会。非可靠信号一般都有确定的用途及含义, 可靠信号则可以让用户自定义使用。

03. 信号产生方式

3.1 当用户按某些终端键时,将产生信号。

终端上按“Ctrl+c”组合键通常产生中断信号 SIGINT,终端上按“Ctrl+\”键通常产生中断信号 SIGQUIT,终端上按“Ctrl+z”键通常产生中断信号 SIGSTOP 等。

3.2 硬件异常将产生信号。

除数为 0,无效的内存访问等。这些情况通常由硬件检测到,并通知内核,然后内核产生适当的信号发送给相应的进程。

3.3 软件异常将产生信号。

当检测到某种软件条件已发生,并将其通知有关进程时,产生信号。

3.4 调用 kill() 函数将发送信号。

注意:接收信号进程和发送信号进程的所有者必须相同,或发送信号进程的所有者必须是超级用户。

3.5 运行 kill 命令将发送信号。

此程序实际上是使用 kill 函数来发送信号。也常用此命令终止一个失控的后台进程。

04. kill发送信号

#include <sys/types.h>
#include <signal.h>int kill(pid_t pid, int sig);
功能:给指定进程发送指定信号(不一定杀死)参数:pid : 取值有 4 种情况 :pid > 0:  将信号传送给进程 ID 为pid的进程。pid = 0 :  将信号传送给当前进程所在进程组中的所有进程。pid = -1 : 将信号传送给系统内所有的进程。pid < -1 : 将信号传给指定进程组的所有进程。这个进程组号等于 pid 的绝对值。sig : 信号的编号,这里可以填数字编号,也可以填信号的宏定义,可以通过命令 kill - l("l" 为字母)进行相应查看。不推荐直接使用数字,应使用宏名,因为不同操作系统信号编号可能不同,但名称一致。返回值:成功:0失败:-1

注意:使用 kill() 函数发送信号,接收信号进程和发送信号进程的所有者必须相同,或者发送信号进程的所有者是超级用户。

测试代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <signal.h>int main(void)
{pid_t pid = -1;pid = fork();if (-1 == pid){perror("fork"); goto err0;}else if (0 == pid){while(1){printf("child process do thing --- Hello uplooking\n"); sleep(1);}exit(0);}printf("parent process do thing\n");sleep(3);//向指定的进程发送指定的信号//kill(pid, SIGKILL);kill(pid, 9);return 0;
err0:return 1;
}

测试结果:

05. pause等待信号

#include <unistd.h>int pause(void);
功能:等待信号的到来(此函数会阻塞)。将调用进程挂起直至捕捉到信号为止,此函数通常用于判断信号是否已到。
参数:无。
返回值:直到捕获到信号才返回 -1,且 errno 被设置成 EINTR。

测试代码:

#include <unistd.h>
#include <stdio.h>int main(int argc, char *argv[])
{printf("in pause function\n");pause();return 0;
}

测试结果:

deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$ gcc 1.c
deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$ ./a.out
in pause function
^C
deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$

没有产生信号前,进程一直阻塞在 pause() 不会往下执行,假如,我们按“Ctrl+c”,pause() 会捕获到此信号,中断当前进程。

06. 信号处理方式

一个进程收到一个信号的时候,可以用如下方法进行处理:

1)执行系统默认动作

对大多数信号来说,系统默认动作是用来终止该进程。

2)忽略此信号

接收到此信号后没有任何动作。

3)执行自定义信号处理函数

用用户定义的信号处理函数处理该信号。

注意:SIGKILL 和 SIGSTOP 不能更改信号的处理方式,因为它们向用户提供了一种使进程终止的可靠方法。

产生一个信号,我们可以让其执行自定义信号处理函数。假如有函数 A, B, C,我们如何确定信号产生后只调用函数 A,而不是函数 B 或 C。这时候,我们需要一种规则规定,信号产生后就调用函数 A,就像交通规则一样,红灯停绿灯行,信号注册函数 signal() 就是做这样的事情。

07. 信号处理函数

#include <signal.h>typedef void (*sighandler_t)(int);// 回调函数的声明
sighandler_t signal(int signum,sighandler_t handler);功能:注册信号处理函数(不可用于 SIGKILL、SIGSTOP 信号),即确定收到信号后处理函数的入口地址。此函数不会阻塞。参数:signum:信号的编号,这里可以填数字编号,也可以填信号的宏定义,可以通过命令 kill -l 进行相应查看。handler: 取值有 3 种情况:SIG_IGN:忽略该信号SIG_DFL:执行系统默认动作信号处理函数名:自定义信号处理函数,如:fun回调函数的定义如下:
void fun(int signo)
{// signo 为触发的信号,为 signal() 第一个参数的值
}注意:信号处理函数应该为可重入函数。返回值:成功:第一次返回 NULL,下一次返回此信号上一次注册的信号处理函数的地址。如果需要使用此返回值,必须在前面先声明此函数指针的类型。失败:返回 SIG_ERR

测试程序一:

#include <stdio.h>
#include <signal.h>
#include <unistd.h>// 信号处理函数
void signal_handler(int signo)
{if(signo == SIGINT){printf("recv SIGINT\n");}else if(signo == SIGQUIT){printf("recv SIGQUIT\n");}
}int main(int argc, char *argv[])
{printf("wait for SIGINT OR SIGQUIT\n");/* SIGINT: Ctrl+c ; SIGQUIT: Ctrl+\ */// 信号注册函数signal(SIGINT, signal_handler);signal(SIGQUIT, signal_handler);// 等待信号pause();pause();return 0;
}

在终端里敲“Ctrl+c”或“Ctrl+\”,自动调用其指定好的回调函数 signal_handler():

deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$ gcc 1.c
deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$ ./a.out
wait for SIGINT OR SIGQUIT
^Crecv SIGINT
^\recv SIGQUIT
deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$

测试程序二:

#include <stdio.h>
#include <signal.h>
#include <unistd.h>// 回调函数的声明
typedef void (*sighandler_t)(int);void fun1(int signo)
{printf("in fun1\n");
}void fun2(int signo)
{printf("in fun2\n");
}int main(int argc, char *argv[])
{sighandler_t previous = NULL;// 第一次返回 NULLprevious = signal(SIGINT,fun1); if(previous == NULL){printf("return fun addr is NULL\n");}// 下一次返回此信号上一次注册的信号处理函数的地址。previous = signal(SIGINT, fun2);if(previous == fun1){printf("return fun addr is fun1\n");}// 还是返回 NULL,因为处理的信号变了previous = signal(SIGQUIT,fun1);if(previous == NULL){printf("return fun addr is NULL\n");}return 0;
}

执行结果:

deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$ gcc 1.c
deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$ ./a.out
return fun addr is NULL
return fun addr is fun1
return fun addr is NULL
deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$

08. 附录

8.1 参考博客:【linux系统编程】进程间通信:信号中断处理

【Linux系统编程】信号 (上)相关推荐

  1. Linux系统编程-信号入门2

    早,继续记录我的学习心得. 分享一个关于机械练习和有目的练习的看法. 机械的练习: 只是埋头干!我刚刚挥起球拍,努力去击球.我刚刚听到了那些数字,想办法去记住.我刚刚看到了那些数学题,正试着解答. 有 ...

  2. Linux系统编程-信号入门3

    早,继续记录我的学习心得. 机械的练习: 只是埋头干!我一直在挥着球拍,努力去击球.我一直在看这道数学题,正试着解答.我一直在重复写代码,试图成为技术大牛. 有准确目的的练习: 意味着要比机械的练习更 ...

  3. 十四、Linux系统编程-信号(一)中断、信号、中断和信号

    一.中断 (1).中断概念       中断是用以提高计算机工作效率.增强计算机功能的一项重要技术.最初引入硬件中断,只是出于性能上的考量.如果计算机系统没有中断,则处理器与外部设备通信时,它必须在向 ...

  4. linux系统发送信号的系统调用是,linux系统编程之信号:信号发送函数sigqueue和信号安装函数sigaction...

    信号发送函数sigqueue和信号安装函数sigaction sigaction函数用于改变进程接收到特定信号后的行为. sigqueue()是比较新的发送信号系统调用,主要是针对实时信号提出的(当然 ...

  5. 【Linux系统编程学习】信号、信号集以其相关函数

    此为牛客Linux C++和黑马Linux系统编程课程笔记. 文章目录 0. 信号的概念 1. Linux信号一览表 2. 信号相关函数 3. kill函数 4. raise函数 5. abort函数 ...

  6. linux 可定义信号数,Linux系统编程(20)——信号基本概念

    信号及信号来源 信号是在软件层次上对中断机制的一种模拟,在原理上,一个进程收到一个信号与处理器收到一个中断请求可以说是一样的.信号是异步的,一个进程不必通过任何操作来等待信号的到达,事实上,进程也不知 ...

  7. Linux系统编程【文件IO、进程、进程间通信、信号、线程、互斥】

    linux系统编程 个人通过学习,手打了一份48000字的Linux系统编程的笔记,包含了[文件IO.进程.进程间通信.信号.多线程.互斥]等知识点,并给出了大量的代码案例对每个重要的知识点进行了代码 ...

  8. 【Linux系统编程】信号 (下)

    00. 目录 文章目录 00. 目录 01. 信号集 02. 信号阻塞集 03. sigaction函数 04. 附录 01. 信号集 为了方便对多个信号进行处理,一个用户进程常常需要对多个信号做出处 ...

  9. Linux系统编程(四)信号

    Linux系统编程(四)信号 一.什么是信号? 1.信号的本质 2.信号来源 硬件来源 软件来源 二.常见信号 1.可靠信号和不可靠信号 2.不可靠信号主要有以下问题: 3.可靠信号与不可靠信号注册机 ...

最新文章

  1. 新手建议学php吗,关于PHP新手学习的一些指导和建议,新手来我的
  2. Performance comparison Raw device VS Ext2 VS Ext3 VS OCFS
  3. pynlpir.LicenseError: Your license appears to have expired. Try running pynlpir update.
  4. QML使用Python的函数
  5. 通过监测DLL调用探测Mimikatz
  6. 学会这二十个正则表达式,能让你少些1000行代码!
  7. STL(一)——栈及其应用
  8. php+go+to,让phpstrom支持codeigniter框架实现 (GO TO )转到定义的功能
  9. ubuntu使用python读串口_ubuntu16.04上Python串口编程学习1
  10. pat1062. Talent and Virtue (25)
  11. 用思科2610搭建PSTN拨号网络
  12. 【图论】Dijkstra算法解决有向图最短路问题
  13. Python后端实现苹果ID登陆
  14. 三目运算(三目表达式)是什么?
  15. SRM 459 500p hust1080 NumberPyramids
  16. 单模光电转换器怎么接_光纤收发器及其连接方式图解!
  17. GIS矢量数据更新时的瓦片范围计算
  18. 【Chrome】解决浏览器萤幕画面模糊字体不清楚方法
  19. linux下ping提示dup,ping出现dup问题
  20. iframe父页面子页面相互调用方法

热门文章

  1. 混沌分形之逻辑斯蒂(Logistic)映射系统
  2. android 适合mvp模式,Android中的MVP:如何使Presenter层系统化?
  3. python3 面向对象编程_Python3基础-面向对象编程
  4. 浏览器接收响应数据过大_DOM总结:数据通信(HTTP协议和Ajax)
  5. 计算机网络实验类型有哪些,北航研究生计算机网络实验_实验三 网络层实验
  6. 《大道至简》第四章内容总结
  7. 手动创建数据库实例全攻略7:UNDO
  8. 史上比较用心的纯代码实现 AutoLayout
  9. CSS--布局模型,颜色值,长度值
  10. ORA-19573: cannot obtain exclusive enqueue for datafile 1