lhmouse / mcfgthread

Cornerstone of the MOST efficient std::thread on Windows for mingw-w64
https://gcc-mcf.lhmouse.com/
Other
269 stars 28 forks source link

A thread spinning on a CV could miss a wakeup #27

Closed lhmouse closed 7 years ago

lhmouse commented 7 years ago

In ReallyWaitForConditionVariable() from src/condition_variabe.c:

if(bSpinnable){
    for(size_t i = 0; i < uMaxSpinCount; ++i){
        {
            uintptr_t uOld, uNew;
            uOld = __atomic_load_n(puControl, __ATOMIC_RELAXED);
            do {
                bSignaled = !(uOld & MASK_WAITING);
                if(!bSignaled){
                    break;
                }
                uNew = uOld & ~MASK_THREADS_SPINNING;
            } while(_MCFCRT_EXPECT_NOT(!__atomic_compare_exchange_n(puControl, &uOld, uNew, false, __ATOMIC_RELAXED, __ATOMIC_RELAXED)));
        }
        if(_MCFCRT_EXPECT_NOT(bSignaled)){
            (*pfnRelockCallback)(nContext, nUnlocked);
            return true;
        }
        __builtin_ia32_pause();
    }
}

A thread sets MASK_WAITING before it begins spinning and the spinning wait is essentially waiting for that mask to be cleared. But this isn't a reliable protocol. Another thread may break in and set that mask, making the current thread miss the wakeup.

lhmouse commented 7 years ago

I redesigned the CV and this problem should no longer happen, but it still needs testing.