3 回答
TA贡献1848条经验 获得超10个赞
printf()
调用所有函数并不安全,例如 printf
,在信号处理程序中。一种有用的技术是使用信号处理程序来设置 flag
然后检查一下 flag
从主程序中打印一条消息,如果需要的话。
alarm_fired
alarm_fired
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);}
volatile sigatomic_t
signal()
sigaction()
TA贡献1803条经验 获得超3个赞
malloc()
malloc()
ISO/IEC 9899:2011§7.14.1.1 signal
功能
5如果信号发生时不是由于调用 abort
或 raise
函数时,如果信号处理程序引用任何具有静态或线程存储持续时间的对象,而该对象不是无锁原子对象,则行为是未定义的,除非将值赋值给声明为 volatile sig_atomic_t
,或者信号处理程序调用标准库中的除 abort
函数 _Exit
函数 quick_exit
函数,或 signal
函数的第一个参数等于与导致调用处理程序的信号对应的信号。此外,如果对 signal
函数的结果是 SIG_ERR
返回值 errno
是不确定的。 252)252)
如果任何信号是由异步信号处理程序生成的,则该行为是未定义的。
如果进程是多线程的,或者进程是单线程的,并且执行信号处理程序的结果是:
进程调用 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()
<string.h>
_Exit() getppid() sendmsg() tcgetpgrp()
_exit() getsockname() sendto() tcsendbreak()
abort() getsockopt() setgid() tcsetattr()
accept() getuid() setpgid() tcsetpgrp()
access() htonl() setsid() time()
aio_error() htons() setsockopt() timer_getoverrun()
aio_return() kill() setuid() timer_gettime()
aio_suspend() link() shutdown() timer_settime()
alarm() linkat() sigaction() times()
bind() listen() sigaddset() umask()
cfgetispeed() longjmp() sigdelset() uname()
cfgetospeed() lseek() sigemptyset() unlink()
cfsetispeed() lstat() sigfillset() unlinkat()
cfsetospeed() memccpy() sigismember() utime()
chdir() memchr() siglongjmp() utimensat()
chmod() memcmp() signal() utimes()
chown() memcpy() sigpause() wait()
clock_gettime() memmove() sigpending() waitpid()
close() memset() sigprocmask() wcpcpy()
connect() mkdir() sigqueue() wcpncpy()
creat() mkdirat() sigset() wcscat()
dup() mkfifo() sigsuspend() wcschr()
dup2() mkfifoat() sleep() wcscmp()
execl() mknod() sockatmark() wcscpy()
execle() mknodat() socket() wcscspn()
execv() ntohl() socketpair() wcslen()
execve() ntohs() stat() wcsncat()
faccessat() open() stpcpy() wcsncmp()
fchdir() openat() stpncpy() wcsncpy()
fchmod() pause() strcat() wcsnlen()
fchmodat() pipe() strchr() wcspbrk()
fchown() poll() strcmp() wcsrchr()
fchownat() posix_trace_event() strcpy() wcsspn()
fcntl() pselect() strcspn() wcsstr()
fdatasync() pthread_kill() strlen() wcstok()
fexecve() pthread_self() strncat() wmemchr()
ffs() pthread_sigmask() strncmp() wmemcmp()
fork() raise() strncpy() wmemcpy()
fstat() read() strnlen() wmemmove()
fstatat() readlink() strpbrk() wmemset()
fsync() readlinkat() strrchr() write()
ftruncate() recv() strspn()
futimens() recvfrom() strstr()
getegid() recvmsg() strtok_r()
geteuid() rename() symlink()
getgid() renameat() symlinkat()
getgroups() rmdir() tcdrain()
getpeername() select() tcflow()
getpgrp() sem_post() tcflush()
getpid() send() tcgetattr()
write()
printf()
标准C功能和信号安全
为什么大多数字符串函数都是从 <string.h>
的字符类函数。 <ctype.h>
还有更多的C标准库函数不在上面的列表中吗?实现需要有目的邪恶才能实现。 strlen()
从信号处理程序调用不安全。
<string.h>
strlen()
strchr()
, strstr()
strtok()
, strcoll()
strxfrm()
strtok()
strtok()
strcoll()
strxfrm()
<ctype.h>
strcoll()
strxfrm()
.
<math.h>
<complex.h>
, <fenv.h>
<tgmath.h>
.
<stdlib.h>
abs()
malloc()
<assert.h>
— 可能不安全<complex.h>
— 可能安全<ctype.h>
-不安全 <errno.h>
-安全 <fenv.h>
— 可能不安全<float.h>
-没有职能 <inttypes.h>
-区域敏感功能(不安全) <iso646.h>
-没有职能 <limits.h>
-没有职能 <locale.h>
-区域敏感功能(不安全) <math.h>
— 可能安全<setjmp.h>
-不安全 <signal.h>
-允许 <stdalign.h>
-没有职能 <stdarg.h>
-没有职能 <stdatomic.h>
— 可能安全,可能不安全<stdbool.h>
-没有职能 <stddef.h>
-没有职能 <stdint.h>
-没有职能 <stdio.h>
-不安全 <stdlib.h>
-并非所有的安全(有些是允许的;另一些是不允许的) <stdnoreturn.h>
-没有职能 <string.h>
-并非所有的安全 <tgmath.h>
— 可能安全<threads.h>
— 可能不安全<time.h>
-地点依赖性(但 time()
显式允许) <uchar.h>
-地点依赖性 <wchar.h>
-地点依赖性 <wctype.h>
-地点依赖性
<pthread.h>
TA贡献1828条经验 获得超3个赞
如何避免使用 printf
在信号处理器里?
总是避开它,会说:只是不要用 printf()
在信号处理程序中。 至少在POSIX一致性系统上,您可以使用 write(STDOUT_FILENO, ...)
而不是 printf()
..然而,格式化可能并不容易: 使用写或异步安全函数从信号处理程序打印int
- 3 回答
- 0 关注
- 1267 浏览
添加回答
举报