Linux_信号操作

  1. 创建两个子进程;

    子进程1对文件mytest.txt进行写操作,

    每5秒写入一次,

    写入当时的时间。

    子进程2对文件mytest.txt进行读操作,

    每5秒中读一次,

    读取并打印文件中所写入的最新时间。

    读写操作都使用文件锁进行保护。

    main.c

    time_t currtime;

    time(&currtime);

    char *time_string = ctime(&currtime);

  2. 信号

    什么是信号?

    信号是一种事件。

    不能自定义信号,所有信号都是系统预定义的。

    信号由谁产生?

    1) 由shell终端根据当前发生的错误(段错误、非法指令等)而产生相应的信号

    比如:

    socket通信或者管道通信,

    如果读端都已经关闭,

    执行写操作(或者发送数据),

    将导致执行写操作的进程收到SIGPIPE信号

    (表示管道破裂)

    该信号的默认行为:终止该进程。

    2) 在shell终端,使用kill或killall命令产生信号

    实例:main1.c

    ./a.out &

    kill -HUP 13733 /* 向PID为13733的进程发送SIGHUP */

    3) 在程序代码中,调用kill系统调用产生信号

  3. 有哪些信号

    信号名称 说明

    SIGABORT 进程异常终止

    SIGALRM 超时告警

    SIGFPE 浮点运算异常

    SIGHUP 连接挂断

    SIGILL 非法指令

    SIGINT 终端中断 (Ctrl+C将产生该信号)

    SIGKILL *终止进程

    SIGPIPE 向没有读进程的管道写数据

    SIGQUIT 终端退出(Ctrl+\将产生该信号)

    SIGSEGV 无效内存段访问

    SIGTERM 终止

    SIGUSR1 *用户自定义信号1

    SIGUSR2 *用户自定义信号2

    ————————————–>以上信号如果不被捕获,则进程接受到后都会终止!

    SIGCHLD 子进程已停止或退出

    SIGCONT *让暂停的进程继续执行

    SIGSTOP *停止执行(即“暂停”)

    SIGTSTP 中断挂起

    SIGTTIN 后台进程尝试读操作

    SIGTTOU 后台进程尝试写

  4. 信号的捕获

    信号的捕获,是指,指定接受到某种信号后,去执行指定的函数。

    注意:SIGKILL和SIGSTOP不能被捕获,

    即,这两种信号的响应动作不能被改变。

    信号的安装

    1) 使用signal

    用法:man 2 signal

     typedef void (*sighandler_t)(int);
     sighandler_t signal(int signum, sighandler_t handler);
    
    注:signal的返回类型,和它的第二个参数,都是函数指针类型
    
    signal的参数2可去以下特殊值:
    SIG_IGN     忽略信号
    SIG_DFL     恢复默认行为
    
    实例:
    main2.c  改变终端中断信号的行为
    此时就不能结束该进程了!
    只能通过其他终端,给该进程发送一个其他信号,使它终止
         #ps ax | grep ./a.out      //查询进程号
         #kill  -HUP  进程号     
    
    恢复信号的默认行为
    main3.c
    使用SIG_DFL时,
          仅当第一次调用自定义的行为后
          马上使用SIG_DFL就可恢复,
          如果连续捕获多次后,就不确定。
    

    2) 使用sigaction

    sigaction与signal的区别:

    sigaction比signal更“健壮”,建议使用sigaction

    用法:man 2 sigaction

    结构struct sigaction

    struct sigaction {

    void (sa_handler)(int); / 信号的响应函数 */

    sigset_t sa_mask; /* 屏蔽信号集 */

    int sa_flags; /* 当sa_flags中包含 SA_RESETHAND时,接受到该信号并调用

    * 指定的信号处理函数执行之后,把该信号的响应行为重置为默认行为SIG_DFL */

    }

    补充:
    当sa_mask包含某个信号A时,
     则在信号处理函数执行期间,如果发生了该信号A,
     则阻塞该信号A(即暂时不响应该信号),
     直到信号处理函数执行结束。
     即,信号处理函数执行完之后,再响应该信号A
    
    实例:main4.c
             用sigaction改变响应动作
             即:用sigaction改写main2.c
    
             main5.c
             用sigaction恢复默认动作
             用sigaction改写main3.c
    
  5. 信号的发送

    信号的发送方式:

    在shell终端用快捷键产生信号

    使用kill,killall命令。

    使用kill函数和alarm函数

    1) 使用kill函数

    给指定的进程发送指定信号

    用法:man 2 kill

    注意:

    给指定的进程发送信号需要“权限”:

    普通用户的进程只能给该用户的其他进程发送信号

    root用户可以给所有用户的进程发送信号

    kill失败

    失败时返回-1

    失败原因:

    权限不够

    信号不存在

    指定的进程不存在

    实例:main6.c
         创建一个子进程
         子进程每秒中输出字符串“child process work!"
         父进程等待用户输入,
               如果用户按下字符A, 则向子进程发信号SIGUSR1,
                                           子进程的输出字符串改为大写
               如果用户按下字符a, 则向子进程发信号SIGUSR2,
                                           子进程的输出字符串改为小写
    

    实例:main7.c

    “闹钟”

    创建一个子进程

    子进程在5秒钟之后给父进程发送一个SIGALRM

    父进程收到SIGALRM信号之后,“闹铃”(用打印模拟)

    2)使用alarm函数

    作用:在指定时间之内给该进程本身发送一个SIGALRM信号。

    用法:man 2 alarm

    注意:时间的单位是“秒”

    实际闹钟时间比指定的时间要大一点。

    如果参数为0,则取消已设置的闹钟。

    如果闹钟时间还没有到,再次调用alarm,则闹钟将重新定时

    每个进程最多只能使用一个闹钟。

    返回值:
             失败:返回-1
             成功:返回上次闹钟的剩余时间(秒)
    
    实例:“闹铃”
             main8.c
             用alarm改写main7.c
    

    3) 使用raise

    给本进程自身发送信号。

    原型: int raise (int sig)

  6. 发送多个信号:
    某进程正在执行某个信号对应的操作函数期间(该信号的安装函数),
    如果此时,该进程又多次收到同一个信号(同一种信号值的信号),则:
             如果该信号是不可靠信号(<32),则只能再响应一次。
           如果该信号是可靠信号(>32),则能再响应多次(不会遗漏)。
           但是,都是都必须等该次响应函数执行完之后,才能响应下一次。
    

    某进程正在执行某个信号对应的操作函数期间(该信号的安装函数),

    如果此时,该进程收到另一个信号(不同信号值的信号),则:

    如果该信号被包含在当前信号的signaction的sa_mask(信号屏蔽集)中,

    则不会立即处理该信号。

    直到当前的信号处理函数执行完之后,才去执行该信号的处理函数。

    否则:

    则立即中断当前执行过程(如果处于睡眠,比如sleep, 则立即被唤醒)

    而去执行这个新的信号响应。

    新的响应执行完之后,再在返回至原来的信号处理函数继续执行。

    例:main4_2.c
    
  7. 信号集

    1). 什么是信号集

    信号集,用sigset_t类型表示,实质是一个无符号长整形。

    用来表示包含多个信号的集合。

    2). 信号集的基本操作

    sigemptyset 把信号集清空

    sigfillset 把所有已定义的信号填充到指定信号集

    sigdelset 从指定的信号集中删除指定的信号

    sigaddset 从指定的信号集中添加指定的信号

    sigismember   判断指定的信号是否在指定的信号集中
                              如果是,    返回 1
                              如果不是, 返回 0
                              信号无效, 返回-1
    
    详细用法见  man
    

    3) 进程的“信号屏蔽字”

    进程的“信号屏蔽字”是一个信号集

    想目标进程发送某信号时,如果这个信号在目标进程的信号屏蔽字中,

    则目标进程将不会捕获到该信号,即不会执行该信号的处理函数。

    当该进程的信号屏蔽字不再包含该信号时,则会捕获这个早已收到的信号(执行对应的函数)

    修改进程的“信号屏蔽字”
    使用sigprocmask
    int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
    
    参数:
         how:
               SIG_BLOCK      把参数set中的信号添加到信号屏蔽字中
               SIG_UNBLOCK  把参数set中的信号从信号屏蔽字中删除
               SIG_SETMASK  把参数set中的信号设置为信号屏蔽字
    
         oldset
              返回原来的信号屏蔽字
    
     例:main4_3.c
    

    4) 获取未处理的信号

    当进程的信号屏蔽字中信号发生时,这些信号不会被该进程响应,

    可通过sigpending函数获取这些已经发生了但是没有被处理的信号

    用法: man sigpending

    返回值:成功则返回0

    失败则返回-1

    5) 阻塞式等待信号

    (1) pause

    阻塞进程,直到发生任一信号后

    (2) sigsuspend

    用指定的参数设置信号屏蔽字,然后阻塞时等待信号的反生。

    即,只等待信号屏蔽字之外的信号

    6) 使用sigaction结构中的sa_flags标志

    sigaction函数的参数使用struct sigaction

    struct sigaction结构有sa_flags标志:

    SA_RESETHAND 指定的信号处理函数执行之后,

    把该信号的响应行为重置为默认行为SIG_DFL

    SA_NOCLDSTOP 子进程停止时,不产生SIGCHLD信号

    SA_NODEFER 默认情况下,当某信号的处理函数正在执行时,

    该信号将被添加到进程的信号屏蔽字中,

    以防止当前信号处理函数没有处理完时,

    如果又发生该信号而导致该信号处理函数再次运行。

    该信号的处理函数执行完之后,再把该信号从该进程的信号屏蔽字中删除。

                                      以上默认设置的原因:
                                      如果信号处理函数是“不可重入”的,则被打断后重新执行,将产生错误!
                                      以上默认设置,可避免同一信号反复出现而使该信号处理函数,
                                                            在未执行完的情况下反复执行。
    
                                      如果使用SA_NODEFER,将使得该信号不会添加到信号屏蔽字中。
    
        SA_RESTART          默认情况下,可中断的Linux的系统调用在执行期间,
                                      如果收到一个信号,则该系统调用将返回一个错误,
                                                                  并设置errno为EINTR
    
                                      如果使用SA_RESTART,
                                      则该信号处理函数执行完之后,
                                      被该信号中断的系统调用将被重新执行,
                                      而不是简单地返回一个错误。
    
  8. 函数的“可重入”

    在信号处理函数中,应只能调用“可重入”的函数。

    因为信号处理函数在执行期间,很可能被中断。

    不可重入的函数在上次运行未完成就结束后,

    当再次运行时,就可能发生问题!

    例如 :printf函数就是不可重入的。

    所以在信号处理函数中,不应调用printf

           解决办法:
           在信号处理函数中,设置一个标志,
           在信号处理函数之外去判断这个标志,
           根据这个标志的状态来使用printf
    

附录:

Linux的信号:

不可靠信号

1) SIGHUP

2) SIGINT

3) SIGQUIT

4) SIGILL

5) SIGTRAP

6) 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

没有定义32和33

时间: 2024-10-13 20:13:20

Linux_信号操作的相关文章

linux_后台启动多个java -jar 程序,及关闭

启动脚本 startup.sh #!/bin/bash x=$(($1)) while (($x>0)) do java -jar /home/chenpenghui/crawler/crawler-hb/StartUpIp.jar & sleep 3 x=$(($x-1)) done 线程数 等于 输入值 启动如下 ./startup.sh 10 停止脚本 clean.sh #!/bin/bash kill -9 `ps ax|grep /home/chenpenghui/crawler/

Linux_防火墙入门00:IEC_ ISO _IEEE简介

主题是Linux_防火墙,这跟IEC/ISO/IEEE好像牵扯不到关系吧?其实不然,恰恰是很多IT教育工作者忽略它的重要性,如果从源头去引导学生,更利于他们理解IT技术概念,当然这也需要教育工作者本身有一定的知识基础. 当然,现实中我们也遇到这些概念,也许某一天,你遇到Boss向你咨询"xxx, 你的系统安全按照哪个标准做的?",此时当然你会回答是ISO13335,因为ISO13335是一个信息安全管理指南,这个标准的主要目的就是要给出如何有效地实施IT安全管理的建议和指南. 从事IT

【linux_笔记】Linux_文件查找(find)详解&&特殊权限

学习资源来自:www.magedu.com 学习记录过程中难免出现错误,如有发现,还望大神们指出. 示例操作部分有的与历史操作有关,如果先前的示例操作没有执行过的话,可能会有部分示例的操作无法执行.示例仅供参考(练习题在附录). 文件查找: locate(不常用):非实时,模糊匹配,根据全系统文件数据库进行查找,速度快:# updatedb, 手动生成文件数据库(非常耗时) find:实时,精确,支持众多查找标准,遍历指定目录中的所有文件完成查找,速度慢: 命令格式:find 查找路径 查找标准

linux_常用命令_(ls, lsof,nslookup)_查看文件按照时间排序

平时收集些用到的命令 方便使用 1:  ls -lrt 按时间排序  展示 2:nslookup  查看dns解析 3:lsof -p 进程号 lsof `which httpd` //那个进程在使用apache的可执行文件lsof /etc/passwd //那个进程在占用/etc/passwdlsof /dev/hda6 //那个进程在占用hda6lsof /dev/cdrom //那个进程在占用光驱lsof -c sendmail //查看sendmail进程的文件使用情况lsof -c

Linux_解决启动网卡失败 Device eth0 does not seem to be present

Linux_解决启动网卡失败  Device eth0 does not seem to be present 虚拟机克隆  发现service network restart 启动失败 故障现象: service network restartShutting down loopback insterface:                                                                                             

Linux_用户管理&权限管理

2017年1月11日, 星期三 Linux_用户管理&权限管理 1.  Linux用户管理&权限管理 终端的概念: tty  查看登录的终端 类型  user group    other   硬链接次数     属主   属组       大小         修改时间           文件名 d       rwx            r-x         r-x              3             sxt    sxtgod     4096       J

Linux_创建母版,快速克隆,如何移动虚拟机.ziw

2017年1月9日, 星期一 Linux_创建母版,快速克隆,如何移动虚拟机 1. 安裝虚拟机 2. 建立母版--第一次启动虚拟机    2.1 设置网卡为NAT模式   2.2 配置虚拟机IP   2.3 删除网卡设备与配置文件映射关系文件   2.4 设置开机关闭防火墙 2.5 关闭selinux 2.6 重启网络   2.7 检查--ping 2.8 设置dns服务 2.9 关机,马上拍照,克隆 poweroff 3. 克隆其他主机 3.1 修改主机名及主机IP vi /etc/sysco

Linux_笔记_01_设置静态IP与 SecureCRT连接Linux

步骤一至三,即可设置好静态IP 步骤四至九,使SecureCRT连接Linux 步骤一:编辑ifcfg-eth0 文件 1.打开ifcfg-eth0 文件 使用命令:vi /etc/sysconfig/network-scripts/ifcfg-eth0 2.编辑ifcfg-eth0文件 按英文 I  进入vim编辑模式. 进行编辑,上图红框部分是必须要有的.将IPADDR设置为你想要的静态ip DVICE=eth0 HWADDR=00:50:56:2A:E2:56 TYPE=Ethernet

Linux_破解密码-营救模式

实验用机:CentOS 5.7 破解密码 设置开机启动界面 系统运行级别 营救模式 一.破解密码 root用户可以更改任何用户的密码,普通用户只能修改自己的密码. 步骤: 1.重新启动系统 2.开机倒数时间内,敲任意键 3.按字母e去编辑 4.选择kernel 开头的行,再次按字母e 编辑 然后敲空格 输入数字1,再敲回车 进入单用户模式,破解密码.(此模式绕过密码验证) 5.按字母键b 去引导进入系统 6.直接passwd 修改root用户的密码 7.输入init 5或者init 3 进入系统