怎么做PSELECT块使用信号屏蔽在网络编程
目前我正在网络编程中我碰到的功能PSELECT的一个(附带的概念),它解决了选择,即问题的信号。使用select(),在intr_flag的测试和选择的调用之间有问题,如果信号发生,如果永远选择块,它将会丢失。怎么做PSELECT块使用信号屏蔽在网络编程
if (intr_flag)
handle_intr(); /* handle the signal */
if ((nready = select(...)) < 0) {
if (errno == EINTR) {
if (intr_flag)
handle_intr();
}
然而,它说,随着PSELECT,我们现在可以代码这个例子中可靠地
sigset_t newmask, oldmask, zeromask;
sigemptyset(&zeromask);
sigemptyset(&newmask);
sigaddset(&newmask, SIGINT);
sigprocmask(SIG_BLOCK, &newmask, &oldmask); /* block SIGINT */
if (intr_flag) //here
handle_intr(); /* handle the signal */
if ((nready = pselect (... , &zeromask)) < 0) {
if (errno == EINTR) { //here
if (intr_flag)
handle_intr();
}
...
}
,它给出的代码是可靠的解释是 - 测试intr_flag变量之前,我们阻止SIGINT。当pselect被调用时,它用空集(即零掩码)替换进程的信号掩码,然后检查描述符,可能会进入睡眠状态。但是,当pselect返回时,在调用pselect(即SIGINT被阻止)之前,进程的信号掩码会重置为其值。
但与PSELECT上面的代码中提到的,我们阻止信号那么如何才能检查错误EINTR?由于pselect会阻塞所有信号,因此当发生中断时,它应该阻止中断或被传送到进程。只有当pselect返回时才能传递信号。
根据在其前面的评论这里提及,中断或仍然可能发生信号PSELECT被调用之前在两者之间的第一检查和PSELECT或当PSELECT称为矛盾阻挡中断的目的,行任何其他信号,因此应该导致竞争条件,因为选择在那里。
请谁能解释这是怎么可能的,因为我是新来的这些概念。
好了,主要的想法是,这样做ready = pselect(nfds, &readfds, &writefds, &exceptfds, timeout, &sigmask);
相当于执行以下操作原子:
sigset_t sigsaved;
sigprocmask(SIG_SETMASK, &sigmask, &sigsaved);
/* NB: NOTE-1 */
ready = select(nfds, &readfds, &writefds, &exceptfds, timeout);
sigprocmask(SIG_SETMASK, &sigsaved, NULL);
要利用这一点,我们第一块,比方说,SIGINT
:
sigset_t emptyset, blockset;
sigemptyset(&blockset);
sigaddset(&blockset, SIGINT);
sigprocmask(SIG_BLOCK, &blockset, NULL);
那时我们不能收到SIGINT
,因此我们无法处理它。但我们不需要它,直到我们输入pselect()
。我们想要做的 我们已经封锁SIGINT
后什么是设置一个适当的信号处理程序。我们有一个标志static volatile int intr_flag = 0;
在我们的主代码之外声明,我们定义了一个名为handler()
的处理程序,它只是简单地intr_flag = 1;
。因此,我们将其设置为一个处理程序:
sa.sa_handler = handler;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
sigaction(SIGINT, &sa, NULL);
然后我们配置readfs
(声明没有显示在这里), 初始化一个空的信号设定和调用pselect()
:
sigemptyset(&emptyset);
ready = pselect(nfds, &readfds, NULL, NULL, NULL, &emptyset);
因此,我将概述这一个更多的时间 - 我们没有收到SIGINT
,直到我们叫pselect()
。我们不需要它。只要我们输入pselect()
,信号SIGINT
将被解除阻塞(因为提供给pselect()
的空信号集),并且pselect()
可以被SIGINT
中断。 而此时pselect()
回报,我们再不会在pselect()
收到任何进一步SIGINT
,但如果SIGINT
发生点,那么我们将其检测为每errno
为EINTR
,如果我们检查intr_flag
,我们会发现它是1
。我们会理解,我们需要相应的行为。所以,很明显信号处理器可以在信号解除阻塞后立即完成工作,而后者发生在pselect()
调用本身内。
最重要的这里的细节是,如果我们没有特殊pselect()
呼叫原子方式来实现,那么我们有使用普通select()
时做上述自己的片断周围/* NB: NOTE-1 */
标签的步骤。而且,因为它不会是原子,我们将有机会在两个操作之间将SIGINT
交付给我们 - 其中/* NB: NOTE-1 */
提示所在位置,即在我们解除信号传递并且在输入select()
之前。那时信号确实会丢失。这就是为什么我们需要拨打pselect()
。
总而言之,原子性的pselect()
是其使用的解释。 如果你对这个概念不太熟悉,你可以参考维基百科上的article或计算机科学主题的专门书籍。
此外,我会提供我的答案,连接到LWN上的article,这是更详尽的。
很好的解释:)谢谢! –
不客气。 –