Is static local variables safe for a class that creates/uses std::thread
s?
Because when I use something like this:
logger& logger::get_instance(void)
{
static logger lg;
return lg;
}
And try to exit (force close) the executable, it crashes/exits improperly (somethings the Visual Studio 2012 debugger even crashes).
When I don't do that, the program exits gracefully when i force close.
Here's the stack call when it crashes
ntdll.dll!77c10dbd() Unknown
[Frames below may be incorrect and/or missing, no symbols loaded for ntdll.dll]
ntdll.dll!77b7bfdc() Unknown
kernel32.dll!75b55bab() Unknown
> msvcr110d.dll!__crtCreateThreadpoolWait(void (_TP_CALLBACK_INSTANCE *, void *, _TP_WAIT *, unsigned long) * pfnwa, void * pv, _TP_CALLBACK_ENVIRON_V1 * pcbe) Line 569 C
msvcr110d.dll!Concurrency::details::RegisterAsyncWaitAndLoadLibrary(void * waitingEvent, void (_TP_CALLBACK_INSTANCE *, void *, _TP_WAIT *, unsigned long) * callback, void * data) Line 675 C++
msvcr110d.dll!Concurrency::details::ExternalContextBase::PrepareForUse(bool explicitAttach) Line 120 C++
msvcr110d.dll!Concurrency::details::ExternalContextBase::ExternalContextBase(Concurrency::details::SchedulerBase * pScheduler, bool explicitAttach) Line 52 C++
msvcr110d.dll!Concurrency::details::SchedulerBase::GetExternalContext(bool explicitAttach) Line 1579 C++
msvcr110d.dll!Concurrency::details::SchedulerBase::AttachExternalContext(bool explicitAttach) Line 1527 C++
msvcr110d.dll!Concurrency::details::SchedulerBase::CreateContextFromDefaultScheduler() Line 569 C++
msvcr110d.dll!Concurrency::details::SchedulerBase::CurrentContext() Line 402 C++
msvcr110d.dll!Concurrency::details::LockQueueNode::LockQueueNode(unsigned int timeout) Line 616 C++
msvcr110d.dll!Concurrency::critical_section::lock() Line 1017 C++
msvcp110d.dll!mtx_do_lock(_Mtx_internal_imp_t * * mtx, const xtime * target) Line 65 C++
msvcp110d.dll!_Mtx_lock(_Mtx_internal_imp_t * * mtx) Line 144 C++
escobar.exe!std::_Mtx_lockX(_Mtx_internal_imp_t * * _Mtx) Line 68 C++
escobar.exe!std::_Mutex_base::lock() Line 43 C++
escobar.exe!std::unique_lock<std::mutex>::unique_lock<std::mutex>(std::mutex & _Mtx) Line 228 C++
escobar.exe!escobar::utilities::blocking_queue<escobar::logging::log_message *>::interrupt() Line 71 C++
escobar.exe!escobar::logging::log_worker::~log_worker() Line 17 C++
escobar.exe!escobar::logging::log_worker::`scalar deleting destructor'(unsigned int) C++
escobar.exe!escobar::logging::logger::close() Line 72 C++
escobar.exe!escobar::logging::logger::~logger() Line 27 C++
escobar.exe!`escobar::logging::logger::get_instance'::`2'::`dynamic atexit destructor for 'lg''() C++
msvcr110d.dll!doexit(int code, int quick, int retcaller) Line 585 C
msvcr110d.dll!_cexit() Line 410 C
msvcr110d.dll!__CRTDLL_INIT(void * hDllHandle, unsigned long dwReason, void * lpreserved) Line 296 C
msvcr110d.dll!_CRTDLL_INIT(void * hDllHandle, unsigned long dwReason, void * lpreserved) Line 210 C
ntdll.dll!77bb2846() Unknown
ntdll.dll!77bb2893() Unknown
ntdll.dll!77bc09c8() Unknown
ntdll.dll!77bc08ad() Unknown
KernelBase.dll!75525bbb() Unknown
KernelBase.dll!75525c51() Unknown
kernel32.dll!75b58543() Unknown
ntdll.dll!77bbac69() Unknown
ntdll.dll!77bbac3c() Unknown
Here are a couple of the functoin
log_worker::~log_worker(void)
{
this->queue.interrupt();
service.join();
}
void log_worker::run(void)
{
while (true)
{
log_message* msg;
if (this->queue.dequeue(msg) == false)
break;
this->lg->print_log_message(msg);
delete msg;
}
}
bool dequeue(T& item)
{
std::unique_lock<std::mutex> lock(m);
// handles spurious wakeups
while (!this->data_available && !this->interrupted)
cv.wait(lock);
if (this->interrupted)
return false;
item = std::move(this->front());
this->pop();
if (this->empty())
this->data_available = false;
return true;
}
void interrupt(void)
{
std::unique_lock<std::mutex> lock(m);
this->interrupted = true;
cv.notify_all();
printf("notified threads...\n");
}
So while static variables are "shared between threads" you have to be very careful what you do with them, or things get very unpredictable, very quickly.
Thread SafetyStatic variables are not thread safe. Instance variables do not require thread synchronization unless shared among threads. But, static variables are always shared by all the threads in the process.
Local variables are stored in each thread's own stack. That means that local variables are never shared between threads. That also means that all local primitive variables are thread safe.
Static variables are indeed shared between threads, but the changes made in one thread may not be visible to another thread immediately, making it seem like there are two copies of the variable.
Looks like you have a detached thread SchedulerBase
(could be any scheduled thread which still uses logger
) which is still running while your application is stopped and logger
is destroyed which caused the crash.
And log_worker is dynamically allocated in the logger class.
logger
instance are shutdown properly before logger
is destroyedI simply had to stop deleting things on shutdown. When you close the console using the 'X' button, it's not a proper shutdown, so It's pointless trying to shutdown threads.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With