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);
select和pselect函数原型的说明:
Select和pselect都是等待一系列的文件描述符(int)的状态发生变化。
这两个函数基本上是一致,但是有三个区别:
第一点 select函数用的timeout参数,是一个timeval的结构体(包含秒和微秒),然而pselect用的是一个timespec结构体(包含秒和纳秒)
第二点 select函数可能会为了指示还剩多长时间而更新timeout参数,然而pselect不会改变timeout参数
第三点 select函数没有sigmask参数,当pselect的sigmask参数为null时,两者行为时一致的。有sigmask的时候,pselect相当于如下的select()函数,在进入select()函数之前手动将信号的掩码改变,并保存之前的掩码值;select()函数执行之后,再恢复为之前的信号掩码值。
sigset_t origmask;
sigprocmask(SIG_SETMASK, &sigmask, &origmask);
select(nfds, &readfds, &writefds, &exceptfds, timeout);
sigprocmask(SIG_SETMASK, &origmask, NULL);
例如:
- 1:sigset_t new, old, zero;
- 2:
- 3:sigemptyset(&zero);
- 4:sigemptyset(&new);
- 5:sigaddset(&new, SIGINT);
- 6:sigprocmask(SIG_BLOCK, &new, old);//block SIGINT
- 7:if (intr_flag)
- 8: handle_intr();//handle the signal
- 9:if ((nready = pselet(..., &zero)) < 0){
- 10: if (errno = EINTR){
- 11: if (intr_flag)
- 12: handle_intr();
- 13: }
- 14: ...
- 15:}
如果没有sigprocmask(SIG_BLOCK, &new, old)这行代码阻塞信号,程序执行完7,8行之后,你投递INT,于是INT立即被处理,然后进入9行阻塞。
你本意是发送INT进入handle_intr()处理信号,然后pselect全然不知情的阻塞了。
如果有sigprocmask(SIG_BLOCK, &new, old)这行代码,那么你要么在sigprocmask之前投递了INT,那么INT立即被处理,那么7,8行就可以被正确的处理。要么你在sigprocmask之后投递的INT,那么INT不会被处理,一直到pselect取消了阻塞,INT被处理。这个过程保证了你在处理一个信号结果的同时不会再有该信号被处理。