在我的应用程序中,有一个io线程,专用于
应用程序通过不同的线程处理数据。此外,要求还规定未确认的窗口大小应为1,即随时都应只有一条待处理的未确认消息。这意味着,如果io-
thread在套接字上调度了一条消息,它将不会再发送任何消息,直到它听到来自接收方的确认为止。应用程序的处理线程通过管道与io线程通信。如果有人从Linux
CLI输入ctrl + C,则应用程序需要正常关闭。因此,鉴于这些要求,我有以下选择
我有以下问题
select()和poll()之间的决定。我的应用程序仅处理少于50个文件描述符。可以假设我选择select或poll都没有区别吗?
在select()和pselect()之间进行决策。我阅读了Linux文档,并说明了信号和select()之间的竞争状态。我没有信号的经验,所以有人可以更清楚地说明比赛条件和select()吗?这与有人在CLI上按ctrl + C且应用程序没有停止有关吗?
pselect和ppoll()之间的决定?对一个人的任何想法
我建议通过与select()
vs 开始比较poll()
。Linux还提供pselect()
和ppoll()
;和和(vs
和)的额外const sigset_t *
参数对每个“
p变量”具有相同的作用。如果您不使用信号,那么您就没有竞争的机会,因此,基本问题实际上是关于效率和易于编程的问题。pselect()``ppoll()``select()``poll()
至于比赛:一旦开始使用信号(无论出于何种原因),您将了解到,信号处理程序通常应设置一个类型变量,volatile sig_atomic_t
以指示已检测到信号。造成这种情况的根本原因是,许多库调用都不是可重入的,并且可以在您处于此类例程“中间”时传递信号。例如,仅将消息打印到流样式的数据结构(例如stdout
(C)或cout
(C
++))会导致重新进入问题。
假设您有使用volatile sig_atomic_t flag
变量(可能是catch)的代码,SIGINT
如下所示(另请参见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 ...
...
现在,在代码主体中,您可能希望“运行直到被中断”:
while (!got_interrupted) {
... do some work ...
}
这很好,直到您开始需要进行等待某些输入/输出的html" target="_blank">调用(例如select
或)为止poll
。“等待”操作需要等待该I / O,但 也
需要等待SIGINT
中断。如果您只写:
while (!got_interrupted) {
... do some work ...
result = select(...); /* or result = poll(...) */
}
那么可能会 在 您调用select()
或
之前poll()
而不是之后发生中断。在这种情况下,您确实被打断了,并且变量got_interrupted
被设置了,但是在那之后,您开始等待。您应该got_interrupted
在开始等待之前而不是之后检查变量。
您可以尝试编写:
while (!got_interrupted) {
... do some work ...
if (!got_interrupted)
result = select(...); /* or result = poll(...) */
}
这会缩小“竞赛窗口”,因为现在您可以在“执行一些工作”代码时检测到中断(如果发生);但是仍然存在竞争,因为中断可能 在 您测试变量 后立即 发生,而
在 选择或轮询 之前 发生。
解决方案是使用sigprocmask
(或在POSIX线程代码中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 */
}
(上面的代码实际上并不是那么好,它只是为了说明而不是为了效率而设计的-稍微不同地进行信号屏蔽操作,并以不同的方式放置“中断”测试会更加有效)。
但是,直到您真正开始需要捕获之前SIGINT
,您只需要比较select()
和poll()
(并且如果您开始需要大量的描述符,则某些基于事件的东西(例如,epoll()
其中之一)要比任何一个都更有效)。