Linux select()vs ppoll()vs pselect() [英] Linux select() vs ppoll() vs pselect()

查看:96
本文介绍了Linux select()vs ppoll()vs pselect()的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的应用程序中,有一个专用于

In my application, there is a io-thread, that is dedicated for

  1. 以自定义协议包装从应用程序收到的数据
  2. 通过tcp/ip发送数据+自定义协议数据包
  3. 通过tcp/ip接收数据+自定义协议数据包
  4. 解包自定义协议并将数据传递给应用程序.

应用程序通过不同的线程处理数据.此外,要求还规定未确认的窗口大小应为1,即在任何时候都应该只有一个待处理的未确认消息.这意味着,如果io-thread在套接字上调度了一条消息,它将不会再发送任何消息,直到它听到来自接收方的确认为止. 应用程序的处理线程通过管道与io线程通信.如果有人从Linux CLI输入ctrl + C,则应用程序需要正常关闭. 因此,鉴于这些要求,我有以下选择

Application processes the data over a different thread. Additionally, the requirements dictate that the unacknowledged window size should be 1, i.e. there should be only one pending unacknowledged message at anytime. This implies that if io-thread has dispatched a message over the socket, it will not send any more messages, till it hears an ack from the receiver. Application's processing thread communicates to io-thread via pipe. Application needs to shut gracefully if someone from linux CLI types ctrl+C. Thus, given these requirements, i have following options

  1. 在套接字和管道描述符上使用PPoll()
  2. 使用Select()
  3. 使用PSelect()

我有以下问题

  1. select()和poll()之间的决定.我的应用程序仅处理少于50个文件描述符.可以假设我选择select还是poll都可以吗?

  1. The decision between select() and poll(). My application only deals with less than 50 file descriptors. Is it okay to assume there would be no difference whether i choose select or poll ?

  1. select()和pselect()之间的决定.我阅读了Linux文档,并说明了信号和select()之间的竞争状况.我没有信号的经验,所以有人可以更清楚地说明比赛条件和select()吗?

  1. Decision between select() and pselect(). I read the linux documentation and it states about race condition between signals and select(). I dont have experience with signals, so can someone explain more clearly about the race condition and select() ? Does it have something to do with someone pressing ctrl+C on CLI and application not stopping?

pselect和ppoll()之间的决定?关于一个与另一个的任何想法

Decision between pselect and ppoll() ? Any thoughts on one vs the other

推荐答案

我建议先从select()poll()开始比较. Linux还提供了pselect()ppoll().和pselect()ppoll()的额外const sigset_t *自变量(vs select()poll())对每个"p变量"具有相同的影响.如果您不使用信号,那么您将无所适从,因此基本问题实际上是关于效率和易于编程的问题.

I'd suggest by starting the comparison with select() vs poll(). Linux also provides both pselect() and ppoll(); and the extra const sigset_t * argument to pselect() and ppoll() (vs select() and poll()) has the same effect on each "p-variant", as it were. If you are not using signals, you have no race to protect against, so the base question is really about efficiency and ease of programming.

与此同时,这里已经有一个stackoverflow.com答案:什么是轮询和选择之间的区别.

Meanwhile there's already a stackoverflow.com answer here: what are the differences between poll and select.

对于种族:一旦开始使用信号(无论出于何种原因),您就会了解到,通常,信号处理程序应该只设置类型为volatile sig_atomic_t的变量以表明已检测到信号.这样做的根本原因是,许多库调用不是重新进入,这样,您就可以在常规"过程中传递信号.例如,仅将消息打印到流式数据结构(例如stdout(C)或cout(C ++))会导致重新输入问题.

As for the race: once you start using signals (for whatever reason), you will learn that in general, a signal handler should just set a variable of type volatile sig_atomic_t to indicate that the signal has been detected. The fundamental reason for this is that many library calls are not re-entrant, and a signal can be delivered while you're "in the middle of" such a routine. For instance, simply printing a message to a stream-style data structure such as stdout (C) or cout (C++) can lead to re-entrancy issues.

假设您有使用volatile sig_atomic_t flag变量的代码,也许是捕获SIGINT的类似代码(另请参见

Suppose you have code that uses a volatile sig_atomic_t flag variable, perhaps to catch SIGINT, something like this (see also http://pubs.opengroup.org/onlinepubs/007904975/functions/sigaction.html):

volatile sig_atomic_t got_interrupted = 0;
void caught_signal(int unused) {
    got_interrupted = 1;
}
...
    struct sigaction sa;
    sa.sa_handler = caught_signal;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART;
    if (sigaction(SIGINT, &sa, NULL) == -1) ... handle error ...
    ...

现在,在代码主体中,您可能希望运行直到被中断":

Now, in the main body of your code, you might want to "run until interrupted":

    while (!got_interrupted) {
         ... do some work ...
    }

这很好,直到您开始需要进行等待某些输入/输出的调用,例如selectpoll. 等待"操作需要等待该I/O,但是 也需要等待SIGINT中断.如果您只写:

This is fine up until you start needing to make calls that wait for some input/output, such as select or poll. The "wait" action needs to wait for that I/O—but it also needs to wait for a SIGINT interrupt. If you just write:

    while (!got_interrupted) {
        ... do some work ...
        result = select(...); /* or result = poll(...) */
    }

然后可能会在调用select()poll()之前而不是之后发生中断.在这种情况下,您确实被打断了-并且变量got_interrupted被设置了-但是在那之后,您开始等待.您应该在开始等待之前而不是之后检查got_interrupted变量.

then it's possible that the interrupt will happen just before you call select() or poll(), rather than afterward. In this case, you did get interrupted—and the variable got_interrupted gets set—but after that, you start waiting. You should have checked the got_interrupted variable before you started waiting, not after.

您可以尝试编写:

    while (!got_interrupted) {
        ... do some work ...
        if (!got_interrupted)
            result = select(...); /* or result = poll(...) */
    }

这会缩小竞赛窗口",因为现在您可以在执行一些工作"代码时检测到中断,如果发生了,就可以了;但还是有一场比赛,因为中断可以在您测试变量后之后发生,而在 select-or-poll之前发生.

This shrinks the "race window", because now you'll detect the interrupt if it happens while you're in the "do some work" code; but there is still a race, because the interrupt can happen right after you test the variable, but right before the select-or-poll.

解决方案是使用sigprocmask(或在POSIX线程代码中,pthread_sigmask)的信号阻止属性使测试,然后等待"序列原子"化:

The solution is to make the "test, then wait" sequence "atomic", using the signal-blocking properties of sigprocmask (or, in POSIX threaded code, pthread_sigmask):

sigset_t mask, omask;
...
while (!got_interrupted) {
    ... do some work ...
    /* begin critical section, test got_interrupted atomically */
    sigemptyset(&mask);
    sigaddset(&mask, SIGINT);
    if (sigprocmask(SIG_BLOCK, &mask, &omask))
        ... handle error ...
    if (got_interrupted) {
        sigprocmask(SIG_SETMASK, &omask, NULL); /* restore old signal mask */
        break;
    }
    result = pselect(..., &omask); /* or ppoll() etc */
    sigprocmask(SIG_SETMASK, &omask, NULL);
    /* end critical section */
}

(上面的代码实际上并不是那么好,它只是为了说明而不是效率-稍稍不同地进行信号屏蔽操作,并以不同的方式放置被打扰的"测试会更有效率).

(the above code is actually not that great, it's structured for illustration rather than efficiency -- it's more efficient to do the signal mask manipulation slightly differently, and place the "got interrupted" tests differently).

不过,直到您真正开始需要捕获SIGINT为止,您只需要比较select()poll()(如果您开始需要大量的描述符,则某些基于事件的内容,例如epoll()是比任何一个都更有效率).

Until you actually start needing to catch SIGINT, though, you need only compare select() and poll() (and if you start needing large numbers of descriptors, some of the event-based stuff like epoll() is more efficient than either one).

这篇关于Linux select()vs ppoll()vs pselect()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆