我正在用 C++ 编写程序。我注意到它获得了一些线程,这些线程的目的是每隔一段时间做一些事情,其中有 3 或 4 个。我决定通过编写一个其他使用这些线程的地方可以订阅的调度程序服务来重构,这应该可以将我随时运行的额外事件线程的数量减少到一个。
我还没有任何代码使用它;在我开始写它之前,我想知道它是否可行,并获得一些关于我的设计的反馈。对我想要完成的事情的简要描述是这样的:
添加事件
- 来电者提供事件和时间表
- 时间表提供事件的下一次发生
- (event, schedule) 对被添加到一个事件队列中
- 中断 sleep 事件线程(即唤醒它)
事件线程主循环
- 尝试获取事件队列中的下一个事件
- 如果没有pending事件,直接跳到4
- 获取下一个事件应该发生的时间
- 休眠直到下一个事件(如果没有等待事件则永远休眠)
- 如果 sleep 因任何原因被打断,则循环回到 1
- 如果 sleep 成功完成,执行当前事件
- 更新队列(删除事件,如果是重复事件则重新插入)
- 跳回1
我做了一些研究,知道可以中断休眠线程,而且我相信只要阻止同时访问事件队列,就不会有任何危险行为。我想唤醒一个线程必须是可能的,java 的 Thread 的 sleep() 调用在某些情况下会抛出 InterruptedException,除非它不依赖于操作系统的底层 sleep 调用,否则它必须以某种方式成为可能。
问题
有人可以评论我的方法吗?这是我最好不要重新发明的轮子吗?具体而言,您如何中断休眠线程,以便在下一条指令处恢复执行,是否可以从中断的线程中检测到这一点?
关于boost的注意事项
我敢打赌你可以用 boost 编写一个调度程序,但它在一台机器上编译和运行,因为没有更好的词组,这是一堆垃圾。我之前在上面编译过 boost 程序,每个拉入 boost 的文件通常需要 30 秒以上的时间来编译。如果我能避免这种恼人的发展障碍,我非常愿意。
附录 - 工作代码 [根据 caf 的建议修改]
这是我生成的有效代码。它已经过初步测试,但已正确处理具有不同延迟的单个事件和重复事件。
这是事件线程的主体:
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
}
这是 sleep 函数:
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;
为了处理通用事件的问题,每个Event
包含一个指向抽象类型action
对象的指针,其子类覆盖action::DoEvent
。此方法从 Event::DoEvent
内部调用。 actions
由它们的事件“拥有”,即如果事件不再需要重新安排,它们将自动删除。
最佳答案
您正在寻找的是pthread_cond_t
对象、pthread_cond_timedwait
和pthread_cond_wait
函数。您可以创建条件变量 isThereAnyTaskToDo 并在事件线程中等待它。添加新事件时,您只需使用 pthread_cond_signal()
唤醒事件线程。
关于c++ - 如何唤醒休眠的 pthread?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12025015/