Description
The ThreadPool destructor will still deadlock when
log4cplus::Initializer initializer;
is at top of main if main starts a thread and in that thread exit(2); is called.
The following will fix the issue and doesn't require log4cplus::Initializer initializer; in main.
- version: 2.0.4
- operating system, CPU, bitness: Windows 10 Enterprise 1809 17763.437, Intel Xeon E5-2670 0 @ 2.60GHz (2 processors), x64
configure
script, or CMake, etc., flags and settings: VS 2017 15.9.11 built using:
msbuild /nologo /m /nr:false /p:"Platform=x64" /p:Configuration=Release /t:log4cplus ".\log4cplus\msvc14\log4cplus.sln"
Note: updated projects to 8.1 and 141 using VS 2017 GUI first
What is happening is that the threadpool threads are not going thru normal run down during exit(…) call so the workers vector isn't empty when the condition_consumers condition is signaled so the predicate check fails. I modified the predicate check to go thru the workers and check if they still exist. If none exist I have to detach() the threads otherwise thread destructor throws when it tries to join a thread. Hope this helps!
SLDR
(Stephen L. De Rudder)
Here is the new ThreadPool destructor:
inline ThreadPool::~ThreadPool()
{
std::unique_lock<std::mutex> lock(queue_mutex);
stop = true;
condition_consumers.notify_all();
condition_producers.notify_all();
pool_size = 0;
condition_consumers.wait(lock,
[this]
{
//return this->workers.empty();
if (this->workers.empty()) {
return true;
} else {
#if defined (_WIN32)
for (std::vector< std::thread >::reverse_iterator i = this->workers.rbegin(); i < this->workers.rend(); ++i) {
HANDLE hThread = i->native_handle();
if (WaitForSingleObject(hThread, 0) != WAIT_OBJECT_0) {
return false;
}
}
for (std::vector< std::thread >::reverse_iterator i = this->workers.rbegin(); i < this->workers.rend(); ++i) {
i->detach();
}
return true;
#else
return false;
#endif
}
});
assert(in_flight == 0);
}