如果我在通知的条件变量上调用wait会发生什么

MRB*_*MRB 7 c++ multithreading condition-variable c++11

假设我有两个线程和一个共享的c ++ 11条件变量.如果thread1调用notify并且在thread2调用之后发生了什么?thread2会永远阻塞,还是会因为thread1的通知调用而继续工作?

编辑:

enum bcLockOperation
{
  bcLockOperation_Light = -1,
  bcLockOperation_Medium = 50,
  bcLockOperation_Heavy = 1
}
class BC_COREDLL_EXP bcCustomMutex
        {
        private:
            bcCustomMutex(const bcCustomMutex&);
            bcCustomMutex& operator=(const bcCustomMutex&);

    protected:
        bcAtomic<int> mFlag;
        bcMutex mMutex;
                    bcConditionVariable mCond;

    public:
        bcCustomMutex() { bcAtomicOperation::bcAtomicInit(mFlag, 0); };
        ~bcCustomMutex() {};

        /*bcMutex(const bcMutex& pOther) = delete;
        bcMutex& operator=(const bcMutex& pOther) = delete;*/

        bcInline void lock(bcLockOperation pLockOperation = bcLockOperation_Medium) 
        {
            bcINT32 lNewLoopCount = static_cast<bcINT32>(pLockOperation);
            bcINT32 lLoopCounter = 0;
            bcINT32 lExpected = 0;
            bcINT32 lLoopCount = bcAtomicOperation::bcAtomicLoad(mFlag, bcMemoryOrder_Relaxed); 

            while (true)
            {
                while(bcAtomicOperation::bcAtomicLoad(mFlag, bcMemoryOrder_Relaxed) != 0 && 
                      lLoopCounter != lLoopCount)
                    ++lLoopCounter;
                bcAtomicOperation::bcAtomicCompareExchangeStrong(
                    mFlag, 
                    &lExpected,
                    lNewLoopCount,
                    bcMemoryOrder_Acquire,
                    bcMemoryOrder_Relaxed);
                if(lExpected == 0)
                {
                    //mMutex.lock();
                    return;
                }
                else if(lLoopCounter == lLoopCount)
                {
                    bcLockGuard<bcMutex> lGuard(mMutex);
                                            mCond.wait(mMutex);

                }
                else
                    continue;
            }
        };
        bcInline void UnLock() 
        { 
            bcAtomicOperation::bcAtomicStore(mFlag, 0, bcMemoryOrder_Relaxed);
            bcUniqueLock<bcMutex> lGuard(mMutex);
                            mCond.notifyOne();
        };
        bcInline bcBOOL TryLock() 
        {
        };
    };
Run Code Online (Sandbox Code Playgroud)

我想编写一个自定义互斥锁,这样每个线程都可以提供一个参数来表示当前线程想要执行的操作的复杂性.如果操作的复杂性很低,其他线程将像循环锁一样处于循环中,但如果操作的复杂性为中等,则每个线程将迭代50次,然后将按条件变量休眠,如果操作非常复杂,则其他线程将直接去睡觉.

现在假设thread1锁定了这个互斥锁,而thread2因为它的loopCounter到达它的结束而正在等待,然后才锁定条件变量的互斥锁,thread1调用条件变量上的notify.现在thread2将一直睡眠,直到另一个线程锁定自定义互斥锁,然后在其上调用unlock.

我是多线程的新手,我想学习.我知道我的类可能包含错误或可能完全错误,但有没有办法纠正这个问题或编写这样的互斥锁的好算法.

另一个问题:我的原子操作是否正确排序?

Pet*_*ker 16

Thread2将阻塞,直到有人调用notify.调用以通知在调用时等待的释放线程.如果没有线程在等待,它们什么都不做.他们没有得救.

  • 请注意,这是事件如何在Windows上运行`SetEvent`和`ResetEvent`的*相反*行为. (3认同)

Dan*_*lKO 10

通常,决定等待的代码和决定通知的代码共享相同的互斥锁.所以thread2永远不会"错过"来自thread1的通知.

这是经典的基于锁的并发队列示例:

void push(int x)
{ 
    lock_guard<mutex> guard{queue_mutex};
    thequeue.push(x);
    not_empty_condition.notify_one();
}

int pop()
{
    unique_lock<mutex> guard{queue_mutex};
    not_empty_condition.wait(guard, []{ return !thequeue.empty(); } );
    int x = thequeue.front();
    thequeue.pop();
    return x;
}
Run Code Online (Sandbox Code Playgroud)

假设线程1和线程正在运行push(),并pop()分别.其中只有一个将一次处于关键部分.

  • 如果thread2具有锁,则它永远不会等待,因为队列不为空(因此"丢失"通知是无害的),或者它在那里等待通知(不会丢失).

  • 如果thread1获得了锁,它将把一个元素放入队列中; 如果thread2正在等待,它将得到正确的通知; 如果thread2仍在等待互斥锁,它将永远不会等待,因为队列中至少有一个元素,因此丢失通知是无害的.

通过这种方式,只有在首先不需要通知时才会丢失通知.

现在,如果您对条件变量有不同的用法,那么"丢失"通知会产生任何后果,我相信您要么具有竞争条件,要么完全使用错误的工具.