signal() 和 ualarm() 与 select() 冲突

Posted

技术标签:

【中文标题】signal() 和 ualarm() 与 select() 冲突【英文标题】:signal() and ualarm() in conflict with select() 【发布时间】:2014-05-09 13:59:30 【问题描述】:

我有一个select() 来每秒更新我的 UI 并处理来自 X11 的用户操作。这是这个源代码的sn-p:

XEvent e;
/* Input file descriptor */
fd_set in_fd;
/* Get the file descriptor of the link with X11 */
int dpy_fd = ConnectionNumber(disp->dpy);

while (!finish) 
  FD_ZERO(&in_fd);
  FD_SET(dpy_fd, &in_fd);

  if (select(dpy_fd+1, &in_fd, 0, 0, &tv)) 
    printf("Event Received!\n");
    XNextEvent(disp->dpy, &e);
    /* do something */
  
  else 
    printf("Timer Fired!\n");
    /* do something else*/
  

到目前为止,一切正常。

同时,我需要使用警报每 500 毫秒做另一件事,所以我实现了这个:

static void timer_handler(int sig)

  signal(SIGALRM, SIG_IGN); /* ignore this signal */
  printf("timer_handler\n");
  signal(SIGALRM, timer_handler); /* reinstall the handler */


int test_timer()

  printf("test_timer\n");

  signal(SIGALRM, timer_handler);
  ualarm(1, 500000); /* every 500 ms */

  return 0;

我每 500 毫秒在我的控制台中获得 timer_handler,但它就像消耗来自 select() 的事件,因为我没有 Timer Fired! 了(不再有用户界面更新)。如果我按下一个键或将鼠标移到 UI 上,我会在控制台中收到 Event Received! 并且警报仍在响应。

select() 是否使用 SIGALRM 信号?我在做什么错?我只想使用select() 来处理 UI 和每 500 毫秒调用一个方法的警报(此方法多路复用硬件性能计数器)。

【问题讨论】:

您的症状与XNextEvent()中的阻塞一致,但我们没有enough information to help you troubleshoot。 另一个很好的例子,说明不测试函数调用错误如何导致安静的一些刺激...... - 代码错过了测试select()是否失败。出错时返回-1 OT:至少在 Linux 上,您需要在每次迭代期间重置传递给 select() 的计时器值(在 tv 中),因为它们可能会被 select() 本身修改。 【参考方案1】:

SIGALRMselect(2) 调用中触发EINTR 错误。您必须检查系统调用是否返回超时、文件描述符事件或错误(以及哪种错误):

while (!finish) 
    int s;

    FD_ZERO(&in_fd);
    FD_SET(dpy_fd, &in_fd);

    s = select(dpy_fd+1, &in_fd, 0, 0, &tv)
    if (s > 0) 
        printf("Event Received!\n");
        XNextEvent(disp->dpy, &e);
        /* do something */
     else if (s == 0) 
        /* This is probably where we should break the loop or reset the
         * select(2) timeout, so... I chose to break it. If you don't
         * do something about it you're gonna end up in a busy wait. */
        break;
     else 
        if (errno == EINTR) 
            /* We've been interrupted by another signal, and it might be
             * because of the alarm(3) (using the SIGALRM) or any other
             * signal we have received externally. */
            continue;
        
        perror("Select failed");
        /* Handle the error properly. */
    

【讨论】:

timer_fired 标志背后的想法是什么? 谢谢费尔南多。使用您的代码,我收到以下错误Select failed: Interrupted system call,我不太明白。我也同意 alk,您能否给我们提供更多关于 flag 解决方案的信息? 对不起,我误解了定时器的原因。我以为您想在每次触发计时器时在 while 循环中做一些事情。现在我删除了它。 再次?从选择(2)? Are you sure? 使用您的解决方案,它似乎有效,但前提是警报值小于选择值。如果我将ualarm(1,1000000)(或alarm(1))和select(...) 设置为每秒触发一次,则永远不会调用警报处理程序。

以上是关于signal() 和 ualarm() 与 select() 冲突的主要内容,如果未能解决你的问题,请参考以下文章

sign signal symbol的区别

Linux信号详解:signal与sigaction函数

Linux信号详解:signal与sigaction函数

Linux信号详解:signal与sigaction函数

多线程下的生产者与消费者模式及(notify()与signal()唤醒的使用和区别)

多线程下的生产者与消费者模式及(notify()与signal()唤醒的使用和区别)