我在多线程应用程序中有一个罕见的 heisenbug,其中主线程,只有这个线程,什么都不做。因为它是一只海森虫,所以很难理解为什么会发生这种情况。
主线程基本上只是循环。在循环中,它检查几个并发优先级队列,其中包含按时间排序的要执行的任务。它弹出一个任务,看看是否该执行它。如果时间到了,它只会将它安排到 TBB 的任务调度程序中(使用一个根任务,它是所有其他任务的父任务)。如果不是时间,任务被再次推送到优先级队列中。这是一个周期。在循环结束时,主线程会休眠很短的时间,我希望在实践中会更长,但这并不是一个真正的问题,我只是不希望它在不必要的时候使用太多资源。
从字面上看:
static const auto TIME_SCHEDULED_TASKS_SPAWN_FREQUENCY = microseconds(250);
while( !m_task_scheduler.is_exiting() ) // check if the application should exit
{
m_clock_scheduler.spawn_realtime_tasks(); // here we spawn tasks if it's time
this_thread::sleep_for( TIME_SCHEDULED_TASKS_SPAWN_FREQUENCY );
}
m_clock_scheduler.clear_tasks();
m_root_task.wait_for_all();
我有一项特殊任务,每秒只记录一条“TICK”消息。它会自动重新安排,直到程序结束。但是,当出现 heisenbug 时,我可以看到“TICK”消失了,并且应用程序除了在非主线程中发生的工作之外没有做任何其他事情。所以看起来只有主线程被触及。
问题可能来自不同的地方,可能在调度逻辑中,但它也是唯一有睡眠调用的线程。睡眠是一个 boost::this_thread::sleep_for()。
我的问题是:Windows(7 64位)是否有可能认为主线程经常处于休眠状态并决定它应该休眠比要求更长的时间或绝对结束?
我希望这是不可能的,但我想确定一下。到目前为止,我在在线文档中没有找到任何精确度。
更新:
我有一个朋友可以系统地重现该错误(在 Windows Vista、Core 2 Duo 上)。我向他发送了一个没有睡眠的版本,另一个使用 condition_variable 重新实现了主循环,这样每次将任务推入队列时,condition_variable 都会唤醒主线程(但仍然有最短的生成时间)。
没有睡眠的版本有效(但速度较慢) - 所以即使我不知道真正的来源,问题似乎也是相关的。
使用 condition_variable 的版本有效 - 这表明睡眠调用无法正常工作?
所以,显然我修复了这个错误,但我仍然不知道为什么特定的睡眠调用有时会阻塞。
更新:
它实际上是由 Boost 代码触发的错误。我找到了这个错误并报告了它,它已经被修复了。我没有检查以前的版本,但它已在 Boost 1.55 中修复