unix编程之信号机制笔记

36 篇文章 0 订阅
6 篇文章 0 订阅

unix编程之信号机制笔记

信号是进程间通信的一种方式,但是写代码中用到该机制并不多,调试程序时需要掌握些,故大概了解即可

基础环境:xcode+iterm+clang+macos

一、信号是什么?

信号是进程通信方式的一种,应该算是比较古老的一种吧。比较直观的一些用处是,譬如键盘上某个按键被按下(很常用的就是停止进程Ctrl+c的SIGINT),或者譬如系统用来停止某进程(进程管理器发送信号强制关闭进程)、或者系统用信号来处理某些严重的错误(一个进程试图向一块不存在的虚拟内存写入数据、或者是一条非法指令)、kill命令也是将信号SIGTERM信号发送给对应进程停止进程。

信号本身是不能携带信息的,这就限制了它作为进程间通信的能力。但是虽然你写代码用不到,但是对进程进行各种操作的时候,实际上很多时候系统都是依赖信号完成的功能。

二、标准信号

标准定义在bits/signum.h中

/* Signal number constants.  Generic version.
   Copyright (C) 1991-2017 Free Software Foundation, Inc.
   This file is part of the GNU C Library.

   The GNU C Library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   The GNU C Library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with the GNU C Library; if not, see
   <http://www.gnu.org/licenses/>.  */

#ifdef  _SIGNAL_H

/* Fake signal functions.  */

#define SIG_ERR  ((__sighandler_t) -1)  /* Error return.  */
#define SIG_DFL  ((__sighandler_t)  0)  /* Default action.  */
#define SIG_IGN  ((__sighandler_t)  1)  /* Ignore signal.  */

#ifdef __USE_UNIX98
# define SIG_HOLD ((__sighandler_t)  2) /* Add signal to hold mask.  */
#endif

/* We define here all the signal names listed in POSIX (1003.1-2008);
   as of 1003.1-2013, no additional signals have been added by POSIX.
   We also define here signal names that historically exist in every
   real-world POSIX variant (e.g. SIGWINCH).

   Signals in the 1-15 range are defined with their historical numbers.
   For other signals, we use the BSD numbers.  */

/* ISO C99 signals.  */
#define SIGINT      2   /* Interactive attention signal.  */
#define SIGILL      4   /* Illegal instruction.  */
#define SIGABRT     6   /* Abnormal termination.  */
#define SIGFPE      8   /* Erroneous arithmetic operation.  */
#define SIGSEGV     11  /* Invalid access to storage.  */
#define SIGTERM     15  /* Termination request.  */

/* Historical signals specified by POSIX. */
#define SIGHUP      1   /* Hangup.  */
#define SIGQUIT     3   /* Quit.  */
#define SIGTRAP     5   /* Trace/breakpoint trap.  */
#define SIGKILL     9   /* Killed.  */
#define SIGBUS      10  /* Bus error.  */
#define SIGSYS      12  /* Bad system call.  */
#define SIGPIPE     13  /* Broken pipe.  */
#define SIGALRM     14  /* Alarm clock.  */

/* New(er) POSIX signals (1003.1-2008, 1003.1-2013).  */
#define SIGURG      16 /* High bandwidth data is available at a socket.  */
#define SIGSTOP     17  /* Stopped (signal).  */
#define SIGTSTP     18  /* Stopped.  */
#define SIGCONT     19  /* Continued.  */
#define SIGCHLD     20  /* Child terminated or stopped.  */
#define SIGTTIN     21  /* Background read from control terminal.  */
#define SIGTTOU     22  /* Background write to control terminal.  */
#define SIGPOLL     23  /* Pollable event occurred (System V).  */
#define SIGIO       SIGPOLL /* I/O now possible (4.2 BSD).  */
#define SIGXCPU     24  /* CPU time limit exceeded.  */
#define SIGXFSZ     25  /* File size limit exceeded.  */
#define SIGVTALRM   26  /* Virtual timer expired.  */
#define SIGPROF     27  /* Profiling timer expired.  */
#define SIGUSR1     30  /* User-defined signal 1.  */
#define SIGUSR2     31  /* User-defined signal 2.  */

/* Nonstandard signals found in all modern POSIX systems
   (including both BSD and Linux).  */
#define SIGWINCH    28  /* Window size change (4.3 BSD, Sun).  */

#define _NSIG       32

/* Archaic names for compatibility. */
#define SIGIOT      SIGABRT /* IOT instruction, abort() on a PDP-11.  */
#define SIGCLD      SIGCHLD /* Old System V name */

#endif  /* <signal.h> included.  */

这里举例几个比较重要常用的信号:

信号值处理动作发出信号的原因
SIGHUP终止进程终端挂起或者控制进程终止
SIGINT终止进程键盘按退出,ctrl+c
SIGQUIT终止进程,并进行内核映像转储键盘按退出,ctrl+/
SIGILL终止进程,并进行内核映像转储非法指令
SIGABRT终止进程,并进行内核映像转储执行abort(3)
SIGFPE终止进程,并进行内核映像转储浮点异常
SIGKILL终止进程kill的终止信号
SIGSEGV终止进程,并进行内核映像转储无效内存引用,sigmentfault
SIGTERM终止进程收到终止信号

三、忽略信号

因为基本上所有的信号都将会终止接收到该信号的进程。对于简单的进程来说完全足够,但是如果是对于一个大型进程,这将会产生一系列后果。

linux提供提供了signal()函数用来处理接收指定的信号,其函数声明如下:

int signal (int sig, __sighandler_t handler);

sig入参是信号枚举值,handler入参则是收到该信号时,会调用handler所指向的函数。

handler处可以传入三种值:SIG_IGN,表示对sig信号进行忽略;SIG_DFL,表示恢复该进程对信号的忽略;返回值为整数的函数地址,函数声明类似于int func(int sig);

现在用一段简单示例代码来让进程忽略SIGINT信号

#include "stdio.h"
#include "unistd.h"
#include "signal.h"

int main() {

    signal(SIGINT, SIG_IGN);

    printf("ignore SIGINT\n");

    sleep(10);

    signal(SIGINT, SIG_DFL);

    printf("handle SIGINT\n");

    return 0;
}

编译执行,SIGINT是在终端执行时,使用ctrl+c命令可以对进程发出该信号

feiqianyousadeMacBook-Pro:yousa yousa$ vim signal1.c
feiqianyousadeMacBook-Pro:yousa yousa$ clang -Wall signal1.c -o signal1
feiqianyousadeMacBook-Pro:yousa yousa$ ls
fork2exec.c signal1.c   test.c
signal1     test        test.dSYM
feiqianyousadeMacBook-Pro:yousa yousa$ ./signal1 
ignore SIGINT
^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^Chandle SIGINT

这里我们可以看到,进程在忽略SIGINT信号之后,对于常用的ctrl+c退出进程命令已经不起作用了

但是可以尝试下ctrl+\停止进程的命令

feiqianyousadeMacBook-Pro:yousa yousa$ ./signal1 
ignore SIGINT

^C^\Quit: 3

可以看到,ctrl+\终止进程的命令依然可以终止该进程。

从上面可以了解到

  1. 对该信号进行忽略后,进程会忽略收到的该信号
  2. 忽略的某种信号,并不会影响进程忽略其他信号

忽略信号、截获信号、同时出现多个信号会如何处理?如何给另一个进程发送信号?

在 Linux 程序中常常利用 SIG_IGN 和 SIG_DFL 屏蔽 SIGINT 和 SIGQUIT 来保证执行

四、处理信号

其实这里与忽略信号比较类似,忽略信号不过是直接使用系统定义的对信号进行忽略,而我们这里则是自己定义一个函数来捕捉信号,当然写的会很简单

#include "stdio.h"
#include "unistd.h"
#include "signal.h"

void catch_sig(int sig) {
    printf("catch the sig : %d\n", sig);
}

int main() {
    signal(SIGINT, (void (*)(int))catch_sig);

    printf("ignore SIGINT\n");

    sleep(10);

    signal(SIGINT, SIG_DFL);

    printf("handle SIGINT\n");

    return 0;
}

注意catch_sig函数类型需要根据你自己的环境相应进行调整,我是在mac环境上,signal要求入参是这样。

feiqianyousadeMacBook-Pro:yousa yousa$ clang -Wall signal2.c -o signal2
feiqianyousadeMacBook-Pro:yousa yousa$ ./signal2
ignore SIGINT
^Ccatch the sig : 2
handle SIGINT

执行,可以看到我们截获到SIGINT信号:)

思考

考虑一种情况,如果进程已经收到了SIGINT信号,现在正在处理该信号,如果又收到了一个SIGINT信号会怎么样呢?如果这时候收到了SIGKILL信号又会怎么样呢?

这个可以简单试验下,这里这次就留到下次笔记自己再进行试验了。

PS

  1. 进程可以向自己发送信号(abort)
  2. SIGKILL。这是一个相当特殊的信号,它从一个进程发送到另一个进程,使接收到该信号的进程 终止。内核偶尔也会发出这种信号。SIGKILL 的特点是,它不能被忽略和捕捉,只能通过 用户定义的相应中断处理程序而处理该信号。因为其它的所有信号都能被忽略和捕捉,所 以只有这种信号能绝对保证终止一个进程
  3. 进程给进程发送信号的命令是使用kill函数,我们也可以通过命令行调用kill来给相应进程发送信号(当然基本是kill掉该进程)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值