boost::this_thread::sleep_for()会死锁
(金庆的专栏)
发现睡眠1ms很容易死锁。
boost::this_thread::sleep_for(boost::chrono::milliseconds(1)).
Boost 1.54.0
以下代码很可能重现死锁:
#include "stdafx.h"#include <iostream>#include <boost/thread.hpp>using namespace std;void worker(){ for (int i = 0; i < 10000; i++) boost::this_thread::sleep_for(boost::chrono::milliseconds(1));}int _tmain(int argc, _TCHAR* argv[]){ boost::thread_group tg; for (int i = 0; i < 30; i++) tg.create_thread(worker); tg.join_all(); cout << "All done!" << endl; return 0;}附加到死锁进程调试时,调用栈如下:
boost::this_thread::interruptible_wait() Line 547
boost::detail::basic_cv_list_entry::wait() Line 94
boost::detail::basic_condition_variable::do_wait<>() Line 228
boost::condition_variable::wait_until<>() Line 371
boost::this_thread::sleep_until<>() Line32
boost::this_thread::sleep_for<>() Line72
worker()
boost::detail::thread_data<>()
程序在停在thread.cpp:547:
unsigned long const notified_index=detail::win32::WaitForMultipleObjects(handle_count, handles, false, using_timer?INFINITE:time_left.milliseconds);
其中
handle_count = 2
using_timer = false
time_left.milliseconds = 0xfffffffe
发现 basic_cv_list_entry::wait(timeout abs_time) 当 abs_time.milliseconds = uint64(-1) 时就会死锁.
所在可以在此断点,将 abs_time.milliseconds 改为 uint64(-1),就可以重现死锁了.
实际上该参数很可能输入为-1:
wait_until(...) { do_wait(lock, ceil<milliseconds>(t-Clock::now()).count()); ... }这几天改服务器代码,添加了许多 sleep_for(), 结果就经常发现服务器停止响应了。
幸好该错误仅在Windows上存在。错误位于 boost/thread/win32/condition_variable.hpp.
正准备给Boost添加条Bug记录,发现该错误已在3周前报告,10天前已修正,将在1.55.0版本中发布。
见:
Condition variable will wait forever for some timepoint values (MSVC)
https://svn.boost.org/trac/boost/ticket/9079
修正代码如下:
chrono::time_point<Clock, Duration> now = Clock::now(); if (t<=now) { return cv_status::timeout; } do_wait(lock, ceil<milliseconds>(t-now).count());