Lodle
Lodle

Reputation: 32197

Race condition in std::thread join

On msvc if you try to join a thread that's not joinable it will call abort. So you have to check if the thread is joinable before calling join but this in it self is a race condition.

void BaseThread::join()
{
    auto thread = m_pPrivates->m_pThread;

    if (!thread)
        return;

    if (thread->get_id() != std::thread::id() && thread->joinable())
        thread->join();
}

Is there away to stop the run time calling abort if a thread is not joinable or a better way to do this?

.

.

.

Edit:

So this is the function that handles thread close in visual studio run time.

int _Thrd_join(_Thrd_t thr, int *code)
{   /* return exit code when thread terminates */
    unsigned long res;

    if (WaitForSingleObject(thr._Hnd, INFINITE) == WAIT_FAILED || GetExitCodeThread(thr._Hnd, &res) == 0)
        return (_Thrd_error);
    if (code)
        *code = (int)res;
    return (CloseHandle(thr._Hnd) == 0 ? _Thrd_error : _Thrd_success);
}

The last line (CloseHandle) is throwing this exception:

Unhandled exception at 0x7750BCEC (ntdll.dll) in desura.exe: 0xC0000008: An invalid handle was specified. Which then crashes the app

Upvotes: 4

Views: 2122

Answers (1)

Adam H. Peterson
Adam H. Peterson

Reputation: 4591

It's not inherently a race condition. A thread remains joinable until it is either joined, detached, or moved-from. These are all things your program has control over, and if another thread is doing one of these things asynchronously to the thread you're trying to join, you obviously have to synchronize. Usually, it's not, though, and you're the owner/manager of the thread.

Note that just because a thread finishes execution, that does not make it unjoinable. In fact, even if you can guarantee that a thread has completed execution, you still have to join with it (or detach it, etc.) to prevent terminate() from being called.

Upvotes: 6

Related Questions