boost::this_thread::sleep_for()死鎖
阿新 • • 發佈:2019-01-10
boost::this_thread::sleep_for()會死鎖
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());
(金慶的專欄)
發現睡眠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());