int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
int pselect(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timespec *timeout, const sigset_t *sigmask)
pselect相对于通常的select有两个变化
(1)timeout支持纳秒。select只支持微妙
(2)最后一个参数sigmask提供指定阻塞信号功能。
不阻塞信号:信号捕获到然后调用信号处理函数。
阻塞信号:信号捕获后,内核记录发生该信号,阻塞信号,不调用信号处理函数。等到设置不阻塞信号时才调用信号处理函数。
UNP 书本举例子
问题是,在测试intr_flag和调用select之间如果有信号发生,那么若select永远阻塞,该信号将丢失。
这里的意思是,1-3行,和4行之间如果SIGINT发生了,并且调用了信号处理函数(该函数只负责把intr_flag设置为1),那么以后将没有机会进行if(intr_flag)的判断,该信号就被永远忽略了。所以我们在第1行前就要开始阻塞信号,从而信号要么在第一行处理,要么在第6行处理。
1:if(intr_flag){
2: handle_intr();
3:}
4:if ((nready = select(..., &zero)) < 0){
5: if (errno = EINTR){
6: if (intr_flag)
7: handle_intr();
8: }
9: ...
10:}
1:sigset_t new, old, zero;
2:
3:sigemptyset(&zero); //初始化
4:sigemptyset(&new);
5:sigaddset(&new, SIGINT); //在new中添加SIGINT信号
6:sigprocmask(SIG_BLOCK, &new, &old);//new是新的包含sigint,old是旧的
7:if (intr_flag)
8: handle_intr();//handle the signal
9:if ((nready = pselect(..., &zero)) < 0){
10: if (errno = EINTR){
11: if (intr_flag)
12: handle_intr();
13: }
14: ...
15:}
上面的第6行设置sigprocmask阻塞SIGINT,因此如果在第6行前发生SIGINT信号,则会在第7行处理这个信号。如果在第6行后发生的,由于信号被阻塞,只记录,不调用信号处理函数,那么则会在第9行pselect处理。zero为不阻塞任何信号,此时可以出现SIGINT信号,并且可以调用SIGINT信号处理函数。pselect跳出阻塞后,会恢复之前的new信号集,继续阻塞。