Dmi*_*sev 5 c++ epoll pthreads
我正在使用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
}
Run Code Online (Sandbox Code Playgroud)
该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. */
}
Run Code Online (Sandbox Code Playgroud)
添加信号处理程序的方法:
#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);
}
Run Code Online (Sandbox Code Playgroud)
要为信号设置此处理程序,请执行以下SIGUSR1操作:
if (-1 == signal_handler_set(SIGUSR1, signal_handler))
{
perror("signal_handler_set() failed");
}
Run Code Online (Sandbox Code Playgroud)
从另一个进程发送信号SIGUSR1:
if (-1 == kill(<target process' pid>, SIGUSR1))
{
perror("kill() failed");
}
Run Code Online (Sandbox Code Playgroud)
要让进程向自身发送信号:
if (-1 == raise(SIGUSR1))
{
perror("raise() failed");
}
Run Code Online (Sandbox Code Playgroud)