Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What happens if i call wait on a notified condition variable

Suppose I have two threads and one shared c++ 11 condition variable. What whould happen if thread1 call notify and after that thread2 call wait? Will thread2 block forever or it will continue it's work due to call of notify by thread1?

Edit:

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() {};

    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)
            {
                return;
            }
            else if(lLoopCounter == lLoopCount)
            {
                bcLockGuard<bcMutex> lGuard(mMutex);
                mCond.wait(mMutex);                           
            }
            else
            {
                continue;
            }
        }

        void UnLock() 
        { 
            bcAtomicOperation::bcAtomicStore(mFlag, 0, bcMemoryOrder_Relaxed);
            bcUniqueLock<bcMutex> lGuard(mMutex);
            mCond.notifyOne();
        }

        bcBOOL TryLock() 
        {
        };
    };

I want to write a custom mutex such that each thread can provide an argument that represents the complexity of operations that the current thread wants to execute. If the complexity of the operation is low other threads will be in a loop like a spin lock but if the complexity of the operation is medium each thread will iterate 50 times and then will sleep by condition variable and if operation is very complex other threads will go to sleep directly.

now assume thread1 locks this mutex and thread2 goes for waiting due to its loopCounter reaching its end and right before locking the condition variable's mutex, thread1 calls notify on the condition variable. Now thread2 will sleep until another thread locks the custom mutex and then calls unlock on it.

I am new to multithreading and I want to learn. I know that my class may contain errors or may be completely wrong, but is there any way to correct this problem or a good algorithm to write such a mutex.

like image 441
MRB Avatar asked Oct 02 '13 16:10

MRB


People also ask

Why do we use while statement instead of IF statement in a wait on a condition variable?

The reason of necessity of using while loop is there are only two functions in the std::condition_variable for awakening waiting threads: notify_one() which awakes one of the threads currently waiting for this condition without possibility to point which one to awake exactly.

What is Condition_variable in CPP?

The condition_variable class is a synchronization primitive that can be used to block a thread, or multiple threads at the same time, until another thread both modifies a shared variable (the condition), and notifies the condition_variable .

Does condition variable need mutex?

Condition variables are used to wait until a particular condition predicate becomes true. This condition predicate is set by another thread, usually the one that signals the condition. A condition predicate must be protected by a mutex.

Which of the system call creates a condition variable?

A condition variable is created by calling the pthread_cond_init subroutine. You may specify a condition attributes object. If you specify a NULL pointer, the condition variable will have the default attributes.


2 Answers

Thread2 will block until someone calls notify. Calls to notify release threads that are waiting at the time of the call. If there are no threads waiting, they do nothing. They aren't saved.

like image 192
Pete Becker Avatar answered Sep 24 '22 15:09

Pete Becker


Usually both the code that decides to wait and the code that decides to notify share the same mutex. So thread2 will never "miss" the notify from thread1.

Here's the classic lock-based concurrent queue example:

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;
}

Assume thread1 and thread2 are running push() and pop() respectively. Only one of them will be in the critical section at a time.

  • If thread2 has the lock, either it never waits because the queue is not empty (so "losing" a notify is harmless), or it sits there waiting for a notify (which won't be lost).

  • If thread1 got the lock, it will put an element in the queue; if thread2 was waiting, it will get notified properly; if thread2 was still waiting for the mutex, it will never wait, as there is at least one element on the queue, so losing a notify is harmless.

In this manner, a notify is only lost if it was not needed in the first place.

Now, if you have a different usage for condition variables in mind, where "losing" a notification has any consequence, I believe you either have a race condition, or are using the wrong tool altogether.

like image 31
DanielKO Avatar answered Sep 22 '22 15:09

DanielKO