自printf不是可重入的,在信号处理程序中使用它是不安全的。但我见过很多示例代码
您可以使用一些标志变量,在信号处理程序中设置该标志,并基于该标志调用。printf()在正常运行过程中,在main()或程序的其他部分中起作用。
调用所有函数并不安全,例如printf,在信号处理程序中。一种有用的技术是使用信号处理程序来设置flag然后检查一下flag从主程序中打印一条消息,如果需要的话。
注意,在下面的示例中,信号处理程序ding()设置了一个标志alarm_fired以1作为SIGALRM的捕获和主要功能alarm_fired值进行检查,以便有条件地正确调用printf。
static int alarm_fired = 0;void ding(int sig) // can be called asynchronously{ alarm_fired = 1; // set flag}int main(){ pid_t pid; printf("alarm application starting\n"); pid = fork(); switch(pid) { case -1: /* Failure */ perror("fork failed"); exit(1); case 0: /* child */ sleep(5); kill(getppid(), SIGALRM); exit(0); } /* if we get here we are the parent process */ printf("waiting for alarm to go off\n"); (void) signal(SIGALRM, ding); pause(); if (alarm_fired) // check flag to call printf printf("Ding!\n"); printf("done\n"); exit(0);}
参考资料:开始Linux编程,第4版,在这本书中,您的代码将被解释(您想要什么),第11章:过程和信号,第484页。
此外,在编写处理程序函数时需要特别小心,因为它们可以异步调用。也就是说,处理程序可以在程序的任意点调用,这是不可预测的。如果两个信号在很短的间隔内到达,一个处理程序可以在另一个处理程序内运行。人们认为更好的做法是宣布volatile sigatomic_t,这种类型总是以原子方式访问,避免了中断对变量访问的不确定性。(原文:原子数据存取和信号处理以获得详细的补偿)。
朗读,阅读定义信号处理程序*学习如何编写可以使用signal()或sigaction()职能。
授权职能清单手册页,在信号处理程序中调用此函数是安全的。
主要问题是如果信号中断malloc()或者一些类似的函数,内部状态可能暂时不一致,当它在空闲列表和使用列表之间移动内存块时,或者其他类似的操作。如果信号处理程序中的代码调用一个函数,然后调用malloc(),这可能会完全破坏内存管理。
对于在信号处理程序中可以做什么,C标准采取了非常保守的观点:

signal功能

5如果信号发生时不是由于调用abort或raise函数时,如果信号处理程序引用任何具有静态或线程存储持续时间的对象,而该对象不是无锁原子对象,则行为是未定义的,除非将值赋值给声明为volatile sig_atomic_t,或者信号处理程序调用标准库中的除abort函数_Exit函数quick_exit函数,或signal函数的第一个参数等于与导致调用处理程序的信号对应的信号。此外,如果对signal函数的结果是SIG_ERR返回值errno是不确定的。252)
252)如果任何信号是由异步信号处理程序生成的,则该行为是未定义的。
对于在信号处理程序中可以做什么,POSIX要慷慨得多。
信号概念在2008年POSIX版中说:
如果进程是多线程的,或者进程是单线程的,并且执行信号处理程序的结果是:
进程调用abort(),raise(),kill(),pthread_kill(),或sigqueue()若要生成未被阻塞的信号,请执行以下操作
正在解除阻塞并在解除阻塞的调用返回之前传递的挂起信号
如果信号处理程序引用除errno使用静态存储持续时间,而不是将值赋值给声明为volatile sig_atomic_t,或者如果信号处理程序调用在此标准中定义的除下表所列函数之外的任何函数。
下表定义了一组应该是异步信号安全的函数.因此,应用程序可以不受限制地从信号捕获函数调用它们:
_Exit() fexecve() posix_trace_event() sigprocmask()_exit() fork() pselect() sigqueue()…fcntl() pipe() sigpause() write()fdatasync() poll() sigpending()
上表中没有的所有功能都被认为在信号方面是不安全的。在信号存在的情况下,本卷POSIX.1-2008所定义的所有函数在从信号捕捉函数调用或被信号捕获函数中断时都应表现为定义的功能,但有一个例外:当信号中断不安全的函数,而信号捕捉函数调用不安全的函数时,则行为未定义。
获得以下值的操作:errno和将值赋值给errno应该是异步信号安全的。
当信号被传递到线程时,如果该信号的动作指定终止、停止或继续,则整个进程将分别终止、停止或继续。
但是,printf()该列表中明显没有函数族,信号处理程序可能无法安全地调用这些函数。
这个2016年POSIXUPDATE扩展了安全函数列表,特别包括了,这是一个特别有价值的补充(或者说是一个特别令人沮丧的疏忽)。