如何唤醒正在睡觉的pthread? 我正在用C++编写一个程序。我注意到它正在获得一些线程,它们的目的是每隔一段时间做一些事情,其中有3到4个线程。我决定通过编写一个调度程序服务进行重构,其他使用这些线程的地方可以订阅该服务,这将使我在任何时候运行的额外事件线程的数量减少到一个
我还没有任何代码使用它;在我开始写之前,我想知道这是否可行,并获得一些关于我设计的反馈。我想完成的简要描述如下: 添加事件如何唤醒正在睡觉的pthread? 我正在用C++编写一个程序。我注意到它正在获得一些线程,它们的目的是每隔一段时间做一些事情,其中有3到4个线程。我决定通过编写一个调度程序服务进行重构,其他使用这些线程的地方可以订阅该服务,这将使我在任何时候运行的额外事件线程的数量减少到一个,c++,linux,pthreads,sleep,C++,Linux,Pthreads,Sleep,我还没有任何代码使用它;在我开始写之前,我想知道这是否可行,并获得一些关于我设计的反馈。我想完成的简要描述如下: 添加事件 调用者提供事件和时间表 计划提供事件的下一次发生 (事件、计划)对添加到事件队列 中断睡眠事件线程(即唤醒它) 事件线程主循环 尝试获取事件队列中的下一个事件 如果没有未决事件,则直接转到4 获取下一个事件应该发生的时间 睡眠到下一个事件(如果没有等待事件,则永远睡眠) 如果睡眠因任何原因被中断,请返回1 如果睡眠成功完成,则执行当前事件 更新队列(删除事件,如果是重复事件
void Scheduler::RunEventLoop()
{
QueueLock(); // lock around queue access
while (threadrunning)
{
SleepUntilNextEvent(); // wait for something to happen
while (!eventqueue.empty() && e.Due())
{ // while pending due events exist
Event e = eventqueue.top();
eventqueue.pop();
QueueUnlock(); // unlock
e.DoEvent(); // perform the event
QueueLock(); // lock around queue access
e.Next(); // decrement repeat counter
// reschedule event if necessary
if (e.ShouldReschedule()) eventqueue.push(e);
}
}
QueueUnlock(); // unlock
return; // if threadrunning is set to false, exit
}
以下是睡眠功能:
void Scheduler::SleepUntilNextEvent()
{
bool empty = eventqueue.empty(); // check if empty
if (empty)
{
pthread_cond_wait(&eventclock, &queuelock); // wait forever if empty
}
else
{
timespec t = // get absolute time of wakeup
Bottime::GetMillisAsTimespec(eventqueue.top().Countdown() +
Bottime::GetCurrentTimeMillis());
pthread_cond_timedwait(&eventclock, &queuelock, &t); // sleep until event
}
}
最后,增编:
void Scheduler::AddEvent(Event e)
{
QueueLock();
eventqueue.push(e);
QueueUnlock();
NotifyEventThread();
}
相关变量声明:
bool threadrunning;
priority_queue<Event, vector<Event>, greater<Event> > eventqueue;
pthread_mutex_t queuelock; // QueueLock and QueueUnlock operate on this
pthread_cond_t eventclock;
bool线程运行;
优先级队列事件队列;
pthread\u mutex\u t queuelock;//QueueLock和QueueUnlock在此基础上操作
pthread_cond_t eventclock;
为了处理泛型事件的问题,每个
事件
都包含一个指向抽象类型action
的对象的指针,whos子类覆盖action::DoEvent
。此方法是从内部调用的Event::DoEvent
<代码>操作由其事件“拥有”,即,如果事件不再需要重新调度,它们将自动删除。您要查找的是pthread\u cond\u t
对象、pthread\u cond\u timedwait
和pthread\u cond\u wait
函数。您可以创建条件变量isThereAnyTaskToDo并在事件线程中等待它。添加新事件时,您只需使用pthread\u cond\u signal()
唤醒事件线程即可在*NIX平台和Windows上实现多种可能性。计时器线程应该使用事件/条件变量对象上的某种定时等待来等待。在POSIX平台上,您可以使用。在Windows上,您可以选择计算必要的时间增量并在事件句柄上使用WaitForSingleObject()
,也可以将事件对象与或组合使用。Boost也有一些同步原语,您可以使用它们来实现类似于POSIX的原语,但可以移植
更新:
POSIX也有一些计时器功能,请参见我同意的,并且可以使用--pthread\u cond\u timedwait()
来实现您所追求的行为。我只想补充一点,您可以简化事件线程主循环:
pthread\u cond\u timedwait()
等待条件变量,直到下一个事件(如果没有计划的事件,则使用pthread\u cond\u Wait()
等待)您可能希望将队列实现为优先级队列,以便下一个过期事件始终位于最前面。您当前的解决方案包含竞争条件,例如:
QueueLock(); // lock around queue access
bool empty = eventqueue.empty(); // check if empty
QueueUnlock(); // unlock
pthread_mutex_lock(&eventmutex); // lock event mutex (for condition)
if (empty)
{
pthread_cond_wait(&eventclock, &eventmutex); // wait forever if empty
}
考虑如果队列最初为空,但另一个线程与此冲突,并在QueueUnlock()
和pthread\u mutex\u lock(&eventmutex)
之间推送一个新值,会发生什么情况-新事件的唤醒将丢失。还请注意,在SleepUntilNextEvent()
中,您可以访问eventqueue.top()
void Scheduler::RunEventLoop()
{
pthread_mutex_lock(&queuemutex);
while (threadrunning)
{
while (!eventqueue.empty() && e.Due())
{ // while pending due events exist
Event e = eventqueue.top();
eventqueue.pop();
pthread_mutex_unlock(&queuemutex);
e.DoEvent(); // perform the event
e.Next(); // decrement repeat counter
pthread_mutex_lock(&queuemutex);
// reschedule event if necessary
if (e.ShouldReschedule()) eventqueue.push(e);
}
SleepUntilNextEvent(); // wait for something to happen
}
pthread_mutex_unlock(&queuemutex);
return; // if threadrunning is set to false, exit
}
/* Note: Called with queuemutex held */
void Scheduler::SleepUntilNextEvent()
{
if (eventqueue.empty())
{
pthread_cond_wait(&eventclock, &queuemutex); // wait forever if empty
}
else
{
timespec t = // get absolute time of wakeup
Bottime::GetMillisAsTimespec(eventqueue.top().Countdown() +
Bottime::GetCurrentTimeMillis());
pthread_cond_timedwait(&eventclock, &queuemutex, &t); // sleep until event
}
}