在同一个linux线程中运行select()套接字和定时器

时间:2013-11-25 19:45:46

标签: c linux sockets select timer

我正在ucLinux上编写代码以进行套接字通信。我使用select()来读取套接字上的数据。我还有一个20毫秒的计时器(使用setitimer创建)在同一个线程中运行,用于执行并行操作。每次说“系统调用中断”时,我的select函数被阻塞,因为它每隔20毫秒就会在溢出时收到定时器发出的SIGALRM信号。发出EINTR时我尝试重新启动系统,然后再次运行select()。但这不会有帮助,因为我总是每20毫秒通过计时器接收SIGALRM。我不想忽略这个信号,因为它用于执行系统中的其他任务,但我想使用select而不受此信号的影响。有办法处理这个吗?我不能使用像timer_create()这样的函数,因为我正在使用的平台不支持这些函数。所以,我坚持使用setitimer来创建计时器。有什么方法可以在我的代码中独立运行吗?

2 个答案:

答案 0 :(得分:3)

你正在做的事很奇怪。让我们面对现实:计时器是一种古老的,大多数过时的工作机制。这些天几乎每个人都避免像瘟疫这样的信号。在信号回调中你基本上没什么用处(你当然不能像malloc那样调用任何复杂的东西),所以你必须有办法从SIGALRM处理程序中获取计时器通知已经到了主线程 - 你实际上并没有在信号处理程序中完成工作是吗?

所以你有两种策略:使用标准的自管技巧将信号转换为fd上的事件,处理SIGTERMSIGINT之类的事情的“正常”方式等等。您调用socketpairpipe来创建管道,然后从信号处理程序将一个字节写入管道。您从select循环中读取了该字节。您通常将信号的值写为数据,但您可以写任何内容。

另一种策略(更加理智)是完全避免信号混乱和setitimersetitimer是严重遗留问题并导致各种问题(例如,它可能导致getaddrinfo等函数挂起,这个错误仍未在glibc中修复(http://www.cygwin.org/frysk/bugzilla/show_bug.cgi?id=15819)信号对你的健康有害。所以“正常”的策略是使用select的超时参数。你有一个定时器的链接列表,你用来管理代码中定期事件的对象。当你打电话给{ {1}},您使用剩余计时器中最短的超时时间。当select调用返回时,检查是否有任何计时器到期并调用计时器处理程序以及fd事件的处理程序。这是一个标准的应用程序事件循环。这样你的循环代码就可以监听定时器驱动的事件以及fd驱动的事件。你系统上的每个应用程序都使用这种机制的一些变体。

答案 1 :(得分:1)

你可以选择这样做吗?

While(1) {
   int rc = select(nfds, &readfds, &writefds, &exceptfds, &timeout);
   if ((rc < 0) && (errno == EINTR) )
      continue;
   else {
      // some instructions
   }
}

如果这不是您的选项,您可以使用 pselect 向末尾添加一个参数(sigmask),该参数指定在pselect()期间应该阻止的一组信号,请参阅here