5.2.25 · HinglishC++ Programming

std - condition_variable

1,857 words8 min readRead in English

5.2.25 · Coding › C++ Programming


WHY does this exist?

WHAT yeh hai: ek synchronization primitive (#include <condition_variable>) jo std::mutex ke saath milke kaam karta hai (std::unique_lock ke zariye) taaki threads kisi condition ka wait kar sakein.

HOW teen pieces fit hote hain:

  1. Ek shared condition (jaise bool ready, ek queue) jo mutex se protected hai.
  2. Waiter: mutex lock karo → cv.wait(lock, pred) call karo → atomically unlock + so jao.
  3. Notifier: mutex lock karo → condition change karo → cv.notify_one()/notify_all() call karo.
Figure — std - condition_variable

The core API (derived by reasoning, not memorized)

Kyun predicate while hai, if nahi? Standard mein do reasons bake hain:

  1. Spurious wakeups: OS ek waiting thread ko bina kisi notify ke bhi jaga sakta hai. Loop re-check karta hai aur wapas so jaata hai.
  2. Stolen wakeups: notify_all ke saath, kai threads jaagti hain, lekin lock grab karne wali pehli thread akela item consume kar sakti hai. Loop doosron ko re-check karke wapas sone par majboor karta hai.

Producer–consumer queue ko scratch se derive karna

Humein chahiye: shared std::queue<int>, ek std::mutex m, ek std::condition_variable cv.

#include <condition_variable>
#include <mutex>
#include <queue>
#include <thread>
#include <iostream>
 
std::queue<int> q;
std::mutex m;
std::condition_variable cv;
bool done = false;
 
void producer() {
    for (int i = 0; i < 5; ++i) {
        {
            std::lock_guard<std::mutex> lk(m); // lock to mutate shared state
            q.push(i);
        } // unlock BEFORE notify (small optimization, avoids waiter waking & blocking)
        cv.notify_one();                       // ring the doorbell
    }
    {
        std::lock_guard<std::mutex> lk(m);
        done = true;
    }
    cv.notify_all();                           // wake everyone so they can exit
}
 
void consumer() {
    while (true) {
        std::unique_lock<std::mutex> lk(m);    // unique_lock: wait can unlock/relock it
        cv.wait(lk, []{ return !q.empty() || done; }); // sleep until pred true
        while (!q.empty()) {
            int v = q.front(); q.pop();
            std::cout << "got " << v << "\n";
        }
        if (done && q.empty()) break;          // nothing left and producer finished
        // lk auto-unlocks at end of loop scope
    }
}

Doosra example: ek one-shot "go" signal


Common mistakes (Steel-manned)


Flashcards

std::condition_variable kis header mein declare hota hai?
<condition_variable>
Ek thread cv.wait mein kaunsa lock type pass karta hai aur kyun?
std::unique_lock<std::mutex>, kyunki wait ko atomically mutex unlock phir re-lock karna hota hai (lock_guard yeh nahi kar sakta).
cv.wait(lock) atomically kya karta hai?
Mutex unlock karta hai, thread ko notify hone tak sula deta hai, phir return karne se pehle mutex re-acquire karta hai.
Kyun wait condition ko ek loop mein check karna padta hai (ya predicate overload ke zariye)?
Spurious wakeups aur stolen wakeups handle karne ke liye (doosri thread pehle resource consume kar le).
notify_one aur notify_all mein kya fark hai?
notify_one ek waiting thread ko jagata hai; notify_all unhe sabko jagata hai (woh phir lock ke liye contend karte hain).
Notify karne se pehle mutex hold karte hue shared state kyun modify karein?
Lost-wakeup race avoid karne ke liye jahan waiter notification miss kar sake aur hamesha ke liye so jaye.
Kya condition_variable un notifications ko yaad rakhta hai jo tab bheji gayi jab koi wait nahi kar raha tha?
Nahi — notifications lost ho jaati hain agar koi thread currently wait nahi kar rahi; correctness shared predicate/flag se aani chahiye.
Kya notify call karte waqt lock hold karna zaruri hai?
Zaruri nahi, lekin safe pattern yeh hai ki state ko lock ke andar change karo; optimization ke tor par notify karne se pehle unlock kar sakte ho.
cv.wait(lk, pred) kis cheez ke equivalent hai?
while(!pred()) cv.wait(lk);

Recall Feynman: ek 12-saal ke bachche ko explain karo

Socho tum ek worker ho jo pizza ka wait kar rahe ho. Har second oven check karne ki jagah (thakaan = energy waste), tum couch par so jaate ho. Ek rule hai: sone se pehle tum chef se kaho "ready hone par jagao" — aur kitchen chhod do taaki chef cook kar sake. Pizza ready hone par chef chillata hai ("notify!") aur tum jaag jaate ho, double-check karte ho ki pizza sach mein wahan hai (shayad tumne sirf sapna dekha — yeh spurious wakeup hai), aur phir khaate ho. Couch nap = wait, chillana = notify, double-checking = while loop. Is tarah tum sote waqt koi energy use nahi karte lekin kabhi apna pizza miss nahi karte.


Connections

  • std::mutex — woh lock jiske saath condition_variable cooperate karta hai.
  • std::unique_lockwait ke liye required; unlock/relock enable karta hai.
  • std::lock_guard — simpler RAII lock, notifier side mein use hota hai.
  • Producer-Consumer Pattern — canonical use case.
  • std::future and std::promise — higher-level one-shot signaling.
  • Spurious Wakeup — predicate loop ki wajah.
  • std::atomic — lock-free flags ka alternative (lekin efficient blocking nahi).
  • Race Condition / Deadlock — woh bugs jo proper use se prevent hote hain.

Concept Map

wastes CPU

solved by

works with

requires

guards

allows unlock plus relock

atomically

loops on predicate

wakes one

wakes all

changed then signaled by

builds

Busy wait loop

Efficient blocking needed

std::condition_variable

std::mutex

std::unique_lock

Shared condition

cv.wait lock, pred

Unlock then sleep then relock

Handles spurious and stolen wakeups

notify_one

notify_all

Producer consumer queue