Liunx系统编程篇—进程通信(五)信号

原理

对于Linux,信号是软中断,例如下课铃响了,老师要停止讲课。许多重要的程序都需要处理信号。
信号,为 Linux 提供了一种处理异步事件的方法。比如,终端用户输入了ctrl+c来中断程序,会通过信号机制停止一个程序。

概述

每个信号都有一个名字和编号,这些名字都以“SIG”开头,例如“SIGIO ”、“SIGCHLD”等等。
信号定义在**signal.h头文件中,信号名都定义为正整数。
具体的信号名称可以 使用
kill -l**来查看信号 的名字以及序号,
信号是 从1开始编号的,不存在0号信号。kill对于信号0又特殊的应用。

xin@xin-virtual-machine:~/桌面/linkr/进程间通信$ 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
xin@xin-virtual-machine:~/桌面/linkr/进程间通信$

信号的处理

有三种方法,忽略,捕捉,和默认动作

1.忽略信号

大多数信号可以使用这个方式来处理,但是有两种信号不能被忽略(分别是 SIGKILL和SIGSTOP)。因为他们向内核和超级用户提供了进程终止和停止的可靠方法

2.捕捉信号

需要告诉内核,用户希望如何处理某一种信号,说白了就是写一个信号处理函数,然后将这个函数告诉内核。当该信号产生时,由内核来调用用户自定义的函数,以此来实现某种信号的处理。

3.系统默认动作

对于每个信号来说,系统都对应由默认的处理动作,当发生了该信号,系统会自动执行。不过,对系统来说,大部分的处理方式都比较粗暴,就是直接杀死该进程。
具体的信号默认动作可以使用man 7 signal来查看系统的具体定义。在此,我就不详细展开了,需要查看的,可以自行查看。也可以参考 《UNIX 环境高级编程(第三部)》的 P251——P256中间对于每个信号有详细的说明。
了解了信号的概述,那么,信号是如何来使用呢?

其实对于常用的 kill 命令就是一个发送信号的工具,kill 9 PID来杀死进程。比如,我在后台运行了一个 top 工具,通过 ps 命令可以查看他的 PID,通过 kill 9 来发送了一个终止进程的信号来结束了 top 进程。如果查看信号编号和名称,可以发现9对应的是 9) SIGKILL,正是杀死该进程的信号。而以下的执行过程实际也就是执行了9号信号的默认动作——杀死进程。

kill -9 进程PID
kill -SIGKILL 进程PID
ps -aux|grep a.out

这两句实现功能一样。

创建

常用API

信号处理函数的注册

入门版:函数signal
高级版:函数sigaction

信号处理发送函数

1.入门版:kill
2.高级版:sigqueue

在正式开始了解这两个函数之前,可以先来思考一下,处理中断都需要处理什么问题。按照我们之前思路来看,可以发送的信号类型是多种多样的,每种信号的处理可能不一定相同,那么,我们肯定需要知道到底发生了什么信号。另外,虽然我们知道了系统发出来的是哪种信号,但是还有一点也很重要,就是系统产生了一个信号,是由谁来响应?如果系统通过 ctrl+c 产生了一个 SIGINT(中断信号),显然不是所有程序同时结束,那么,信号一定需要有一个接收者。对于处理信号的程序来说,接收者就是自己。

signal函数
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);

函数原型由两部分组成,一个是真实处理信号的函数,另一个是注册函数了。
注册函数:
sighandler_t signal(int signum, sighandler_t handler);函数来说,
signum :信号的编号。
handler :中断函数的指针。

handler函数

真实处理信号的函数:
typedef void (*sighandler_t)(int);中断函数的原型中,有一个参数是 int 类型,显然也是信号产生的类型,方便使用一个函数来处理多个信号。

例子

1.信号的处理,捕捉动作

#include <signal.h>
#include <stdio.h>
//typedef void (*sighandler_t)(int);
//sighandler_t signal(int signum, sighandler_t handler);
void handler(int signum)
{printf("get signum=%d\n",signum);switch(signum){case 2:printf("SIGINT\n");break;case 10:printf("SIGUSR1\n");break;}
}
int main()
{signal(SIGINT,handler);//信号处理函数的注册 2signal(SIGUSR1,handler); // 9while(1);//不让程序退出return 0;
}
//结果xin@xin-virtual-machine:~/桌面/linkr/进程间通信$ ./a.out //按cltr+c
xin@xin-virtual-machine:~/桌面/linkr/进程间通信$ ./a.out
^Cget signum=2
SIGINT
//
xin@xin-virtual-machine:~/桌面/linkr/进程间通信$ ps -aux |grep a.out
xin       19558  100  0.0   4516   852 pts/1    R+   11:23   1:04 ./a.out
xin       19567  0.0  0.0  16188   940 pts/0    S+   11:25   0:00 grep --color=auto a.out//
xin@xin-virtual-machine:~/桌面/linkr/进程间通信$ kill -10 19558
xin@xin-virtual-machine:~/桌面/linkr/进程间通信$ ./a.out
^Cget signum=2
SIGINT
get signum=10
SIGUSR1
//杀死 a.out
kill -9 19558
xin@xin-virtual-machine:~/桌面/linkr/进程间通信$ ./a.out
^Cget signum=2
SIGINT
get signum=10
SIGUSR1
已杀死

2.将kill信号处理发送函数置于程序中,同时也可以使用system来实现kill。
信号处理发送函数

#include<stdio.h>
#include <signal.h>
#include <sys/types.h>
int main(int argc,char **argv)
{int signum=0;int pid=0;char cmd[128]={0};//设置system函数处理命令的大小signum= atoi(argv[1]);//转为整型pid= atoi(argv[2]);//转为整型printf("num=%d\n",signum);printf("pid=%d\n",pid);kill(pid,signum);// sprintf(cmd,"kill -%d %d",signum,pid);// system(cmd);printf("send signal ok\n");return 0;
}
/*
注:
1、atoi (表示 ascii to integer)是把字符串转换成整型数的一个函数。
2、sprintf指的是字符串格式化命令,
函数声明为 int sprintf(char *string, char *format [,argument,…]);,
主要功能是把格式化的数据写入某个字符串中,即发送格式化输出到 string 所指向的字符串。
3、
*/

信号的处理:忽略

#include<stdio.h>
#include <signal.h>
void handler(int signum)
{printf("get signum=%d\n",signum);switch(signum){case 2:printf("SIGINT\n");break;case 10:printf("SIGUSR1\n");break;}}
int main()
{signal(SIGINT,SIG_IGN);//将SIGINT信号(ctrl+C、2)忽略signal(SIGUSR1,SIG_IGN);//将SIGUSR1信号(10)忽略while(1);return 0;
}
实验结果
//会发现ctrl+c与kill -10 pid已经对进程不起作用了,这两个信号被进程忽略。

参考原文

Liunx系统编程篇—进程通信(五)信号相关推荐

  1. Liunx系统编程篇—进程通信(二)无名管道(原理、创建、实战)命名管道(原理、创建、实战)

    一.无名管道 管道,通常指无名管道(之所以叫无名管道是因为,没有文件名),是 UNIX 系统IPC最古老的形式. 特点 (1)它是半双工的(即数据只能在一个方向上流动),具有固定的读端和写端. (2) ...

  2. linux进程通信发送方式,Linux服务器编程——Linux系统编程之进程通信

    进程通信又称IPC IPC方法 方法:管道(最简单) 信号(开销最小) 共享映射区/共享内存(无血缘关系) 本地套接字(最稳定) Linux文件类型: -   文件 d  目录 l   符号链接 s  ...

  3. 【Linux系统编程】进程通信之管道

    1.进程间通信介绍 1.1 进程通信的基本概念 在之前我们已经学习过进程地址空间.Linux 环境下,进程地址空间相互独立,每个进程各自有不同的用户地址空间.任何一个进程的全局变量在另一个进程中都看不 ...

  4. Linux学习之系统编程篇:与产生信号有关的函数

    一.kill kill : 给指定的进程法信号. (1)头文件: #include <sys/types.h>#include <signal.h> (2)函数原型: int ...

  5. linux 进程 控制终端,linux系统编程之进程(五):终端、作业控制与守护进程

    #include#define ERR_EXIT(m) do { perror(m); exit(EXIT_FAILURE); } while(0) int setup_daemon(int, int ...

  6. execlp使用例子_linux系统编程之进程(五):exec系列函数(execl,execlp,execle,execv,execvp)使用...

    本节目标: exec替换进程映像 exec关联函数组(execl.execlp.execle.execv.execvp) 一,exec替换进程映像 在进程的创建上Unix采用了一个独特的方法,它将进程 ...

  7. linux系统编程之进程(五):exec系列函数(execl,execlp,execle,execv,execvp)使用

    本节目标: exec替换进程映像 exec关联函数组(execl.execlp.execle.execv.execvp) 一,exec替换进程映像 在进程的创建上Unix采用了一个独特的方法,它将进程 ...

  8. vbs结束进程代码_物联网学习教程—Linux系统编程之进程控制

    Linux系统编程之进程控制 一.结束进程 首先,我们回顾一下 C 语言中 continue, break, return 的作用: continue: 结束本次循环 break: 跳出整个循环,或跳 ...

  9. 【Linux系统编程】进程概述和进程号

    00. 目录 文章目录 00. 目录 01. 进程概述 02. 进程状态 03. 进程控制块 04. 进程号 05. 进程号相关函数 06. 案例实战 07. 附录 01. 进程概述 我们平时写的 C ...

最新文章

  1. ADS与RealView MDK
  2. Ubuntu、CentOS 解决docker命令权限问题(sudo)
  3. hdu4503 概率
  4. Python环境(基于Pycharm和官方python包)搭建顺序
  5. boost使用split分割字符串
  6. 【LeetCode笔记】62. 不同路径(Java、动态规划)
  7. mapreduce yarn内存参数
  8. c语言自定义一个函数求商和余数,c – 如何在一个步骤中获得商和余数?
  9. Python matplotlib绘制饼图
  10. 微软:程序员们,是时候丢掉 Win 7 了!
  11. java基础知识点整理一
  12. 转-从早到晚被工作追着跑? 10招提高你的工作效率
  13. 一致性哈希和redis分布式集群
  14. 光纤尾纤的型号和作用有哪些?
  15. 狂神Redis学习笔记(已更完)
  16. u3d学习笔记三:U3D脚本的生命周期
  17. sigmaplot画辐射方向图教程
  18. mysql容灾方案_mysql 容灾 灾备 备份
  19. 新路程------imx6 wtd摘要
  20. Flex开发环境,开发工具,开发框架总结

热门文章

  1. otter,阿里巴巴分布式数据库同步系统
  2. 华为鸿蒙系统操作教程_华为鸿蒙系统好用吗 华为鸿蒙系统有什么优缺点
  3. 【qq机器人】欢迎加群通报
  4. PHP自学之路-----静态方法
  5. 大厂Offer拿到手软啊!安卓系列学习进阶视频
  6. Lasso线性回归学习笔记(公式与代码实现)
  7. 【WEB推荐系统设计】学分管理与选课推荐系统方案设计
  8. MongoDB查询条件 lt lte gt gte
  9. 基于PaddlePaddle的视频联合时空建模方法
  10. 在王者荣耀角度下分析面向对象程序设计B中23种设计模式之桥接模式