Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sockets pselect如何在网络编程中使用信号掩码阻止信号_Sockets_Unix_Network Programming_Multiplexing - Fatal编程技术网

Sockets pselect如何在网络编程中使用信号掩码阻止信号

Sockets pselect如何在网络编程中使用信号掩码阻止信号,sockets,unix,network-programming,multiplexing,Sockets,Unix,Network Programming,Multiplexing,我目前正在研究网络编程的概念,在其中我遇到了一个函数pselect,它解决了select ie的问题。有了select,就有可能出现问题,即测试intr_标志和调用select之间,如果出现信号,如果select永远阻塞,它将丢失 if (intr_flag) handle_intr(); /* handle the signal */ if ( (nready = select( ... )) < 0) { if (errno == EINTR) { if (intr_flag)

我目前正在研究网络编程的概念,在其中我遇到了一个函数pselect,它解决了select ie的问题。有了select,就有可能出现问题,即测试intr_标志和调用select之间,如果出现信号,如果select永远阻塞,它将丢失

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_标志变量之前,我们阻塞了SIGINT。调用pselect时,它会用一个空集(即零掩码)替换进程的信号掩码,然后检查描述符,可能会进入睡眠状态。但当pselect返回时,进程的信号掩码将重置为调用pselect之前的值,即SIGINT被阻止

但是在上面提到的pselect代码中,我们阻塞了信号,那么我们如何检查错误EINTR呢?由于pselect会阻止所有信号,因此当中断发生时,它会阻止中断或发送到进程。只有当pselect返回时,才能发送信号

根据前面提到注释的行,在调用pselect之前,或在第一次检查和pselect之间,或调用pselect时,中断信号仍可能发生,这与阻止中断和任何其他信号的目的相矛盾,因此应导致与select相同的竞态条件


请任何人解释这是如何可能的,因为我是新的这些概念

好的,主要思想是doing ready=pselectnfds,&readfds,&writefds,&exceptfds,timeout,&sigmask;相当于以原子方式执行以下操作:

要利用这一点,我们首先阻塞,比如SIGINT:

此时我们无法接收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:

所以,我将再一次概述这一点——在调用pselect之前,我们不会收到SIGINT。我们不需要它。一旦我们进入pselect,信号SIGINT将被解锁,因为提供给pselect的信号集为空,pselect可以被SIGINT中断。 在pselect返回时,我们再次将不会收到任何进一步的SIGINT,但如果在pselect期间发生SIGINT,则我们将根据errno be EINTR检测到这一点,如果我们检查intr_标志,我们将发现它为1。我们会明白,我们需要采取相应的行动。因此,很明显,信号处理程序可以在信号解除阻塞后立即执行其工作,后者发生在pselect调用本身中

这里最重要的细节是,如果我们没有以原子方式实现特殊的pselect调用,那么在使用通常的select调用时,我们必须按照上面代码段中的/*NB:NOTE-1*/label执行步骤。而且,由于它不是原子的,我们将有机会在两个操作之间向我们发送SIGINT,即/*NB:NOTE-1*/hint所在的位置,即在我们取消阻止信号发送之后和输入select之前。到那时,信号确实会丢失。这就是为什么我们需要一个pselect调用

总而言之,pselect的原子性是其使用的解释。 如果你对这样一个概念不太熟悉,你可以参考维基百科上的或关于计算机科学主题的专门书籍


此外,我还将提供一个关于LWN的链接,该链接更加详尽。

好吧,主要思想是准备就绪=pselectnfds、&readfds、&writefds、&exceptfds、timeout和&sigmask;相当于以原子方式执行以下操作:

要利用这一点,我们首先阻塞,比如SIGINT:

此时我们无法接收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:

所以,我将再一次概述这一点——在调用pselect之前,我们不会收到SIGINT。我们不需要它。一旦我们进入pselect,信号SIGINT将被解锁,因为提供给pselect的信号集为空,pselect可以被SIGINT中断。 当pselect返回时,我们再次
sa.sa_handler = handler;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
sigaction(SIGINT, &sa, NULL);
sigemptyset(&emptyset);
ready = pselect(nfds, &readfds, NULL, NULL, NULL, &emptyset);