信号的同步等待和异步等待区别就是信号处理函数的执行与否,异步等待是信号处理函数已经执行了,同步等待是信号处理函数尚未执行。html
异步等待接口:pause() 和 sigsuspend()linux
1. pause()编程
/** * 等待信号 * pause()函数将调用进程/线程挂起,使之进入可中断的睡眠状态,直到传递了一个信号为止。 * 这个信号的动做或者是执行用户定义的信号处理函数,或者是终止进程。若是执行用户定义的 * 信号处理函数,pause()会在信号处理函数执行完毕后返回,若是是终止进程,pause()函数 * 就不返回了,若是内核发出的信号被忽略,那么就不会被唤醒。 * * 成功返回-1,并置errno为EINTER. * * pause函数并不能区分是什么信号触发中断,因此不能使用pause函数来等待特定的信号。 */ #include <unistd.h> int pause(void);
2. sigsuspend()异步
/** * 等待特定信号 * * sigsuspend暂时使用参数mask替换调用进程/线程的信号掩码,而且阻塞直到特定信号 * 发生。若是信号终结了进程,sigsuspend函数不返回,若是信号被捕获,则sigsuspend * 会等到信号处理函数执行完成后才返回,而且调用进程/线程的信号掩码会恢复到调用以前 * 的样子。 * 信号SIGKILL 和 SIGSTOP是没法阻塞的。 * 返回值-1,错误码能够是EINTR(信号中断)或者EFAULT(参数错误) * */ #include <signal.h> int sigsuspend(const sigset_t *mask);
同步信号接收接口有两类:函数
1. sigwait() 、sigwaitinfo()、sigtimedwait(),这三个函数接口略有差别,作的事情相似。都是等待特定信号,若是没有信号则挂起当前进程,有的话当即返回。ui
/** * 等待信号发生 * * 成功返回0,并将信号值存储到参数set中,失败返回一个正的错误码。 * */ #include <signal.h> int sigwait(const sigset_t *set, int *sig);
/** * 等待信号返回 * * 当参数第二个siginfo_t不为空时,内核会将关于该信号更详细的信息存储到该指针指向地址, * 若是有多个信号知足条件,sigwaitinfo只会返回其中一个。 * 成功返回信号值,失败返回-1并置errno * */ #include <signal.h> int sigwaitinfo(const sigset_t *set, siginfo_t *info); /** * 和sigwaitinfo功能同样,只是多了一个时间参数,超时未等到信号当即返回, * 若是时间参数timeout为NULL,则和sigwaitinfo同样。 * 若是timeout两个参数为0,那么sigtimedwait会当即返回。 * */ struct timespec { long tv_sec; /* seconds */ long tv_nsec; /* nanoseconds */ } int sigtimedwait(const sigset_t *set, siginfo_t *info, const struct timespec *timeout);
一般调用上述接口前都须要先调用sigprocmask接口将关注的信号屏蔽,防止被信号处理函数劫走。线程
2. Linux还提供了另一种同步等待信号接口 signalfd指针
/** * 建立一个用于接收信号的文件描述符。 * * 参数fd = -1时,该函数会建立一个文件描述符。 * fd != -1,表示修改操做,通常是修改mask的值,此时fd是以前signalfd的 * 返回值 * * 参数mask表示信号集,关注的信号集合。这些信号的集合应该在调用signalfd函数 * 以前,先调用sigprocmask函数阻塞这些信号,防止被信号处理函数劫走。 * * 参数flags用来控制行为,目前支持的标志位以下: * SFD_CLOEXEC :和普通文件的O_CLOEXEC同样,调用exec函数时,文件描述符 * 会被关闭。 * SFD_NONBLOCK : 控制未来的读取操做,若是执行read操做时,并无信号到来, * 则当即返回失败,并设置errno为EAGAIN。 * * 成功返回文件描述符fd,失败返回-1并置errno * * 返回的描述符fd可用于poll,epoll,select等函数,用来检测描述符fd上面的可读 * 事件。 * * 建立文件描述符后,可使用read函数来读取到来的信号。提供的缓冲区大小最少要 * 放下一个signalfd_siginfo结构体,该结构体以下,若是有多个信号返回,read会 * 返回多个该结构体大小的字节数。 */ #include <sys/signalfd.h> int signalfd(int fd, const sigset_t *mask, int flags); struct signalfd_siginfo { uint32_t ssi_signo; /* Signal number */ int32_t ssi_errno; /* Error number (unused) */ int32_t ssi_code; /* Signal code */ uint32_t ssi_pid; /* PID of sender */ uint32_t ssi_uid; /* Real UID of sender */ int32_t ssi_fd; /* File descriptor (SIGIO) */ uint32_t ssi_tid; /* Kernel timer ID (POSIX timers) uint32_t ssi_band; /* Band event (SIGIO) */ uint32_t ssi_overrun; /* POSIX timer overrun count */ uint32_t ssi_trapno; /* Trap number that caused signal */ int32_t ssi_status; /* Exit status or signal (SIGCHLD) */ int32_t ssi_int; /* Integer sent by sigqueue(3) */ uint64_t ssi_ptr; /* Pointer sent by sigqueue(3) */ uint64_t ssi_utime; /* User CPU time consumed (SIGCHLD) */ uint64_t ssi_stime; /* System CPU time consumed (SIGCHLD) */ uint64_t ssi_addr; /* Address that generated signal (for hardware-generated signals) */ uint16_t ssi_addr_lsb; /* Least significant bit of address (SIGBUS; since Linux 2.6.37) uint8_t pad[X]; /* Pad size to 128 bytes (allow for additional fields in the future) */ };
signalfd建立的文件描述符使用完成以后要调用close函数来关闭该文件描述符:code
/* 关闭文件描述符 */ close(fd);
参考资料:htm
1. 《Linux环境编程,从应用到内核》 高峰,李彬著
2. man signalfd : http://www.man7.org/linux/man-pages/man2/signalfd.2.html