Linux学习笔记16 ——signal函数

1,函数原型

我们需要一个函数告诉进程,当本进程接收到某个信号时,该调用什么对应的函数。类似与JS里注册事件的操作。signal函数就是为了实现这一功能的。

#include <signal.h>
void(*signal(int signo, void(*func)(int)))(int);

这个表达式太复杂了。说明如下:

  1. signal函数有两个输入参数,第一个输入参数为int,代表要捕获的信号名;
  2. 第二个输入参数代表捕获到这个信号后进程要执行的操作,所以它是一个函数指针;
  3. 这个指针指向的函数有一个整型输入参数,代表它处理的信号名,返回void,这个函数称之为信号处理程序或信号捕捉函数;
  4. signal函数返回类型也是个函数指针,指向在此之前的信号处理程序;
  5. 如果出错,返回SIG_ERR;
  6. 如果在进程中该信号被忽略,返回SIG_IGN;
  7. 如果在进程中,该信号按系统默认操作处理,则返回SIG_DFL;

由于表达式太复杂,我们可以用typedef简化表达式

typedef void Sigfunc(int)  //信号处理程序的类型
Sigfunc* signal(int signo, Sigfunc*);

2,例子

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>

static void sig_usr(int); //声明信号处理程序
int main(){   
    //注册SIGUSR1,这本身就是一个预留给用户的信号
    if(signal(SIGUSR1, sig_usr) == SIG_ERR) {
        printf("can't catch SIGUSR1 !\n");
		exit(1);         
    } 
    
    //注册SIGUSR2,这也是一个预留给用户的信号
    if(signal(SIGUSR2, sig_usr) == SIG_ERR) {
        printf("can't catch SIGUSR2 !\n");
		exit(1);         
    } 
    
    // 死循环,为了防止进程退出
    while(1){
        pause();
    }
}

// 定义信号处理程序
static void sig_usr(int signo) {
    printf("received signal %d\n", signo);    
}

这段代码定义了一个简单的信号处理程序,用来打印捕捉到的信号的值。主函数里,把两个信号SIGUSR1和SIGUSR2绑定到这个信号处理程序。

我们将这段代码编译为study_linux,并在后台执行:

➜  code g++ -g -Wall -std=c++11 -o study_linux study_Linux.c
➜  code ./study_linux&
[1] 380

进程ID已经打印出来是380.

然后通过kill命令向该进程发送SIGUSR1和SIGUSR2命令,看执行的效果:

➜  code kill -USR1 380
received signal 10
➜  code kill -USR2 380
received signal 12

尅看到信号的值已经被打印出来了。我们发现SIGUSR1是10,而SIGUSR2是12.

最后,由于我们写的是死循环,所以用kill命令直接杀死这个进程

➜  code kill 380
[1]  + 380 terminated  ./study_linux

不带参数的kill命令发出SIGTERM信号。而我们的程序并未捕捉这个信号(事实上,如果我们愿意,是可以修改代码以捕捉这个信号的,这么做可以在进程退出前做一些清理工作),所以使用系统默认的操作。而系统对该信号的默认操作就是终止。所以收到这个信号后,进程终止。

3,补充

  1. 当我们用fork产生一个子程序的时候,原先注册的信号还能继续用。因为子程序完全复制了父进程的内存印象,以前的信号处理程序还能用;
  2. 当一个进程exec一个程序之后(还记得狸猫换太子吗?),原先捕捉的信号都失效了,改为了默认操作。原因是,原先绑定的信号处理函数在新的程序里已经不可用了。
  3. 所以,当我们用先fork,后exec的套路让两个进程并行运行的时候,第二个进程是不会继承第一个进程的信号处理程序的;
  4. 简单的说就是:真儿子和假儿子的区别。。。。
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值