简体   繁体   中英

What if a condition variable signals to a locked thread?

In the (pseudo-)code below, cond might wake up while it shouldn't, for whatever reason. So I put a while loop there. When it does wake up, it will still consume the lock, so it is guaranteed that in out() only one thread is doing its job.

But what happens if, while there is a spurious wake-up in out() , at the same time in() signals to out() , however at that very moment out() is already locked because of the spurious wake-up. So what happens if the cond signals to a locked thread?

in()
    inLock.lock()
    isEmpty = false
    cond.signal()
    inLock.unlock()

out()
    outLock.lock()
    while isEmpty
        cond.wait(outLock)
    isEmpty = true
    outLock.unlock()


NOTE

Well, to be 100% safe, I know I can use a single mutex for both in() and out() , but the data structure I'm using is 100% safe when input and output happens at the same time; it is a type of a queue. And I think it is a performance compromise to block anything reading out from the queue while filling in some new data or vice versa.

I did consider using semaphores, but the problems is that so many C and C++ libraries don't implement semaphores for whatever reason.

You have to use the same mutex when the in() thread sets isEmpty = false and the out() thread tests while (isEmpty) . Otherwise, this can happen:

  1. out() thread tests isEmpty , finds it is true;
  2. in() thread sets isEmpty to false and signals the condition variable (but no-one wakes up, beacuse no-one is waiting yet);
  3. out() thread calls cond.wait() and blocks forever, despite the fact that the queue is not empty anymore.

Note that in this sequence there hasn't been a spurious wakeup - it's just a plain old race condition.

As long as you update isEmpty with the same mutex held as when you test isEmpty , this interleaving can't happen.

So what happens if the cond signals to a locked thread?

The signal is lost forever. If no threads are waiting for the signal when pthread_cond_signal is called, then pthread_cond_signal does nothing.

Since isEmpty is being read and modified by two different threads, it is an error to access it unprotected. This is essentially what you are doing when you allow in and out to use different lock instances.

Using different lock instances on the same condition variable is a violation of the POSIX API for pthread_cond_wait() (emphasis mine).

The effect of using more than one mutex for concurrent pthread_cond_wait() or pthread_cond_timedwait() operations on the same condition variable is undefined ; that is, a condition variable becomes bound to a unique mutex when a thread waits on the condition variable, and this (dynamic) binding ends when the wait returns.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM