我正在用 C++ 编写一个程序。我注意到它获得了许多线程,其目的是每隔一段时间做一些事情,其中有 3 或 4 个。我决定通过编写一个调度程序服务进行重构,使用这些线程的其他地方可以订阅该服务,这应该可以将我在任何时候运行的额外事件线程的数量减少到只有一个。
我还没有任何使用它的代码;在我开始写它之前,我想知道它是否可能,并获得一些关于我的设计的反馈。我想要完成的简要描述是这样的:
添加事件
- 调用者提供事件和时间表
- 时间表提供事件的下一次发生
- (event, schedule) 对被添加到事件队列中
- 中断睡眠事件线程(即唤醒它)
事件线程主循环
- 尝试获取事件队列中的下一个事件
- 如果没有待处理的事件,直接跳到 4
- 获取下一个事件应该发生的时间
- 休眠直到下一个事件(如果没有等待事件,则永远休眠)
- 如果睡眠因任何原因被中断,则循环回 1
- 如果睡眠成功完成,则执行当前事件
- 更新队列(删除事件,如果是重复事件则重新插入)
- 跳回 1
我做了一些研究,知道有可能中断一个睡眠线程,我相信只要防止同时访问事件队列,就不应该有任何危险的行为。我想唤醒一个线程是可能的,java 的 Thread 的 sleep() 调用在某些情况下会抛出一个 InterruptedException ,除非它不依赖于操作系统的底层 sleep 调用,否则它必须以某种方式成为可能。
问题
任何人都可以评论我的方法吗?这是一个我最好不要重新发明的轮子吗?具体来说,您如何中断睡眠线程以便在下一条指令处恢复执行,并且是否可以从中断的线程中检测到这一点?
关于提升的说明
我敢打赌,你可以编写一个带有 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
}
这是睡眠功能:
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
由他们的事件“拥有”,即如果不再需要重新安排事件,它们会被自动删除。