繁体   English   中英

取消卡在epoll_wait上的线程

[英]Cancelling thread that is stuck on epoll_wait

我正在使用C ++和pthreads进行一些事件处理。 我有一个从我定义的事件队列中读取的主线程,以及一个填充事件队列的工作线程。 队列当然是线程安全的。

工作线程有一个文件描述符列表,并创建一个epoll系统调用来获取这些文件描述符上的事件。 它使用epoll_wait等待fd上的事件。

现在问题。 假设我想彻底终止我的应用程序,我该如何正确取消工作线程? epoll_wait不是pthread(7)的取消点之一,所以它无法在pthread_cancel上做出正确的反应。

工作线程main()看起来像这样

while(m_WorkerRunning) {
    epoll_wait(m_EpollDescriptor, events, MAXEVENTS, -1);
    //handle events and insert to queue
}

线程启动时m_WorkerRunning设置为true ,看起来我可以通过主线程将m_WorkerRunning设置为false 中断线程。 问题在于epoll_wait理论上可以永远等待。

我解决的其他解决方案是:不是永远等待(-1)我可以等待X时隙,然后正确处理无事件情况,如果m_WorkerRunning == false则退出循环并彻底终止工作线程。 主线程然后将m_WorkerRunning设置为false,并且睡眠X.但是我不确定这样的epoll_wait的性能,也不确定什么是正确的X? 500ms的? 1秒? 10秒?

我想听听一些经验丰富的建议!

更多相关信息:fd我正在等待事件,是/dev/input中的设备,所以从技术上讲,我正在做某种输入子系统。 目标操作系统是ARM体系结构上的Linux(最新内核)。

谢谢!

我上面的答案几乎是正确的。 然而,差异非常危险。

如果要发送信号以唤醒epoll_wait ,请不要使用epoll_wait。 你必须使用epoll_pwait ,否则你可能会遇到epoll永远不会醒来的比赛。

信号异步到达。 如果你的SIGUSR1在你检查了关机程序后到达,但在你的循环返回到epoll_wait ,那么信号不会中断等待(因为没有),但程序也不会退出。

这可能是非常可能或极不可能的,这取决于循环花费多长时间与等待花费的时间有关,但这是一种错误。

与ALK的回答另一个问题是,它不检查,为什么等待被中断。 这可能有多种原因,有些原因与您的退出无关。

有关更多信息,请参见pselect的手册页。 epoll_pwait以类似的方式工作。

此外,永远不要使用kill向线程发送信号。 请改用pthread_kill 发送信号时, kill的行为充其量是不确定的。 无法保证正确的线程将接收它,这可能导致不相关的系统调用被中断,或者根本不会发生任何事情。

您可以向线程发送一个信号,该信号将阻塞调用epoll_wait() 如果这样做修改你的代码如下:

while(m_WorkerRunning) 
{
  int result = epoll_wait(m_EpollDescriptor, events, MAXEVENTS, -1);
  if (-1 == result)
  {
    if (EINTR == errno)
    {
      /* Handle shutdown request here. */ 
      break;
    }
    else
    {
      /* Error handling goes here. */
    }
  }

  /* Handle events and insert to queue. */
}

一种添加信号处理程序的方法:

#include <signal.h>

/* A generic signal handler doing nothing */
void signal_handler(int sig)
{
  sig = sig; /* Cheat compiler to not give a warning about an unused variable. */
}

/* Wrapper to set a signal handler */
int signal_handler_set(int sig, void (*sa_handler)(int))
{
  struct sigaction sa = {0};
  sa.sa_handler = sa_handler;
  return sigaction(sig, &sa, NULL);
}

要为信号SIGUSR1设置此处理程序,请执行以下操作:

if (-1 == signal_handler_set(SIGUSR1, signal_handler))
{
  perror("signal_handler_set() failed");
}

从另一个进程发送信号SIGUSR1

if (-1 == kill(<target process' pid>, SIGUSR1))
{
  perror("kill() failed");
}

让进程向自己发送信号:

if (-1 == raise(SIGUSR1))
{
  perror("raise() failed");
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM