Fix a race condition in WindowsThread (port::Thread)
Summary: Fix a race condition when we create a thread and immediately destroy This case should be supported. What happens is that the thread function needs the Data instance to actually run but has no shared ownership and must rely on the WindowsThread instance to continue existing. To address this we change unique_ptr to shared_ptr and then acquire an additional refcount for the threadproc which destroys it just before the thread exit. We choose to allocate shared_ptr instance on the heap as this allows the original thread to continue w/o waiting for the new thread to start running. Closes https://github.com/facebook/rocksdb/pull/3240 Differential Revision: D6511324 Pulled By: yiwu-arbug fbshipit-source-id: 4633ff7996daf4d287a9fe34f60c1dd28cf4ff36
This commit is contained in:
parent
34aa245dd8
commit
fe608e32ab
@ -39,12 +39,17 @@ struct WindowsThread::Data {
|
||||
|
||||
void WindowsThread::Init(std::function<void()>&& func) {
|
||||
|
||||
data_.reset(new Data(std::move(func)));
|
||||
data_ = std::make_shared<Data>(std::move(func));
|
||||
// We create another instance of shared_ptr to get an additional ref
|
||||
// since we may detach and destroy this instance before the threadproc
|
||||
// may start to run. We choose to allocate this additional ref on the heap
|
||||
// so we do not need to synchronize and allow this thread to proceed
|
||||
std::unique_ptr<std::shared_ptr<Data>> th_data(new std::shared_ptr<Data>(data_));
|
||||
|
||||
data_->handle_ = _beginthreadex(NULL,
|
||||
0, // stack size
|
||||
&Data::ThreadProc,
|
||||
data_.get(),
|
||||
th_data.get(),
|
||||
0, // init flag
|
||||
&th_id_);
|
||||
|
||||
@ -53,6 +58,7 @@ void WindowsThread::Init(std::function<void()>&& func) {
|
||||
std::errc::resource_unavailable_try_again),
|
||||
"Unable to create a thread");
|
||||
}
|
||||
th_data.release();
|
||||
}
|
||||
|
||||
WindowsThread::WindowsThread() :
|
||||
@ -129,7 +135,7 @@ void WindowsThread::join() {
|
||||
assert(false);
|
||||
throw std::system_error(static_cast<int>(lastError),
|
||||
std::system_category(),
|
||||
"WaitForSingleObjectFailed");
|
||||
"WaitForSingleObjectFailed: thread join");
|
||||
}
|
||||
|
||||
CloseHandle(reinterpret_cast<HANDLE>(data_->handle_));
|
||||
@ -157,8 +163,9 @@ void WindowsThread::swap(WindowsThread& o) {
|
||||
}
|
||||
|
||||
unsigned int __stdcall WindowsThread::Data::ThreadProc(void* arg) {
|
||||
auto data = reinterpret_cast<WindowsThread::Data*>(arg);
|
||||
data->func_();
|
||||
auto ptr = reinterpret_cast<std::shared_ptr<Data>*>(arg);
|
||||
std::unique_ptr<std::shared_ptr<Data>> data(ptr);
|
||||
(*data)->func_();
|
||||
_endthreadex(0);
|
||||
return 0;
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ class WindowsThread {
|
||||
|
||||
struct Data;
|
||||
|
||||
std::unique_ptr<Data> data_;
|
||||
std::shared_ptr<Data> data_;
|
||||
unsigned int th_id_;
|
||||
|
||||
void Init(std::function<void()>&&);
|
||||
|
Loading…
x
Reference in New Issue
Block a user