【UNIX环境高级编程】信号安全——可重入函数

可重入函数(用于信号处理函数、 且 安全时的叫法),即是在信号处理函数中可以调用的函数,他们是安全的,不安全的如malloc(试想:线程正在调用malloc进行分配,而信号来了,在处理函数里面有调用malloc,那么就很有可能对进程造成破坏,破坏储存区维护的链表)、getpwnam等


可重入函数在处理操作期间,会阻塞任何会引起不一致的信号发送。


试想下面一个情况:

因为在信号处理函数执行时,如果里面执行了低俗系统调用 and 此信号处理函数没有屏蔽其它信号(如SIGUSR1),那么这时若果产生了SIGUSR1信号,那么由将产生中断,调用SIGUSR1的处理函数:

<pre name="code" class="cpp">#include <unistd.h>
#include <signal.h>
#include <stdio.h>

void signal_1(int sig)
{
    printf("Start signal_1...\n");
    //sleep(20);
    malloc memory ...
    printf("End signal_1\n");
}
void signal_2(int sig)
{
    malloc memory ...
    printf("Process signal_2 ,OK\n");
}

int main(int argc, char *argv[])
{
    sigset_t set_1;
    sigemptyset(&set_1);
    struct sigaction sa_1;
    sa_1.sa_handler = &signal_1;
    sa_1.sa_mask = set_1;
    sa_1.sa_flags = SA_RESTART;
    sigset_t set_2;
    sigemptyset(&set_2);
    struct sigaction sa_2;
    sa_2.sa_handler = &signal_2;
    sa_2.sa_mask = set_2;
    sa_2.sa_flags = SA_RESTART;
    
    sigaction(SIGUSR1, &sa_1, NULL);
    sigaction(SIGUSR2, &sa_2, NULL);
    printf("Start pause...(PID:%d)\n", getpid());
    pause();
    return 0;
}


 
 

 
 

上面程序运行,先发送SIGUSR1 然后SIGUSR2,(不注释sleep忽略memory )输出:

 $ ./sigproc
Start pause...(PID:7089)
Start signal_1...
Process signal_2 ,OK
End signal_1

如果是使用了memory调用,好明显这两个信号处理函数也是不可重入的;

那么我们可以知道,如果此时阻塞了SIGUSR2信号,那么signal_1不就安全了吗(忽略其它信号也有影响的情况先)

对的,如果使用sigaction调用了设定了阻塞SIGUSR2,那么就行了,可重入函数就是基于这种思想,看上面粗线那句话。


补充:

errno是线程安全的,也就是每个线程会访问局部的errno

在一个main函数中,如果线程函数里调用低俗系统调用,那么就有可能产生错误、中断,那么errno值会被改变,而main函数调用也出错时,那么errno值就会被改变,

所以,在作为一个通用规则,处理函数最好的写法是:

void sigproc(int sig)
{
	int tmp = errno;
	//信号处理函数真正的操作开始...

      //处理函数任务完成
	errno = tmp;
}




你可能感兴趣的:(【UNIX环境高级编程】信号安全——可重入函数)