Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++11 static local variables and threads

Is static local variables safe for a class that creates/uses std::threads?

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");
    }
like image 219
TheAJ Avatar asked Feb 03 '13 06:02

TheAJ


People also ask

Do threads share static variables in C?

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.

Are static variables thread safe C?

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.

Are local variables in static method thread safe?

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.

Can static variables be shared between threads?

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.


2 Answers

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.

  • You need to make sure all threads who use logger instance are shutdown properly before logger is destroyed
  • delete log_worker in logger destructor
like image 68
billz Avatar answered Oct 22 '22 22:10

billz


I 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.

like image 40
TheAJ Avatar answered Oct 22 '22 22:10

TheAJ