信号是系统用来异步通知一个进程某些事件发生了的机制。从效果上来说,有点像中断。信号发生时,打断原有执行过程,进入信号处理函数(如果注册了的话)或默认处理(忽略或终止程序),结束后恢复原有流程。默认情况下,信号处理过程中可能会被其它信号继续中断,所以需要考虑各种可能的情况,比如库函数重入的问题。信号处理函数执行的上下文是在原有栈帧基础上继续的,所以可以用 setjmp() 和 longjmp()。
一些常见的信号
- SIGABRT
- SIGALRM
- SIGCHLD
- SIGINT
- SIGQUIT
- SIGSEGV
- SIGUSR1
- SIGUSR2
注册信号处理函数
typedef void (*__sighandler_t) (int);__sighandler_t signal (int __sig, __sighandler_t __handler); struct sigaction { union { /* Used if SA_SIGINFO is not set. */ __sighandler_t sa_handler; /* Used if SA_SIGINFO is set. */ void (*sa_sigaction) (int, siginfo_t *, void *); } __sigset_t sa_mask; int sa_flags; }; int sigaction (int __sig, const struct sigaction *__restrict __act, struct sigaction *__restrict __oact);
信号处理函数
#define SIG_ERR ((__sighandler_t) -1) /* Error return. */ #define SIG_DFL ((__sighandler_t) 0) /* Default action. */ #define SIG_IGN ((__sighandler_t) 1) /* Ignore signal. */
产生信号
int kill (__pid_t __pid, int __sig); int raise (int __sig); unsigned int alarm (unsigned int __seconds); void abort (void); int sigqueue (__pid_t __pid, int __sig, const union sigval __val);
信号集
int sigemptyset (sigset_t *__set); int sigfillset (sigset_t *__set); int sigaddset (sigset_t *__set, int __signo); int sigdelset (sigset_t *__set, int __signo); int sigismember (const sigset_t *__set, int __signo);
更多函数
// 进程阻塞直到有信号产生 int pause (void); // 阻塞信号 int sigprocmask (int __how /* = SIG_BLOCK or SIG_UNBLOCK or SIG_SETMASK */, const sigset_t *__restrict __set, sigset_t *__restrict __oset); // 获得未决(已产生但未递送)信号 int sigpending (sigset_t *__set); // 修改信号屏蔽字然后阻塞直到有信号产生 // 与 sigprocmask() + pause() 相比,是原子操作 int sigsuspend (const sigset_t *__set);
sigsetjmp() 和 siglongjmp()
#define sigsetjmp(env, savemask) __sigsetjmp (env, savemask) void siglongjmp (sigjmp_buf __env, int __val);
与 setjmp() 和 longjmp() 相比,如果 savemask 不为 0,使用 siglongjmp() 跳出信号处理函数时会恢复信号屏蔽字。
中断的系统调用
ioctl()、read()、readv()、write()、writev() 针对低速设备(可能会被永远阻塞,如管道、终端、网络等)时可能会被信号打断,如果使用 sigaction() 设置信号处理函数并指定 SA_RESTART 时会重新启动,否则返回 -1 并设置 errno 为 EINTR。
其它概念
- 要注意不可靠的信号,比如在安装信号处理函数后与调用等待函数之间,信号可能会发生。
- 必须注意可重入函数,尤其是 malloc()、free() 等
时间: 2024-11-05 06:24:43