5.2.24 · D5 · HinglishC++ Programming
Question bank — Concurrency — std - thread, std - mutex, std - lock_guard, std - unique_lock
5.2.24 · D5· Coding › C++ Programming › Concurrency — std - thread, std - mutex, std - lock_guard, s
Questions se pehle, ek shared vocabulary reminder taaki koi bhi term neeche use hone se pehle clearly samajh aa jaye:
True ya false — justify karo
Ek mutex us variable ko khud hi atomic bana deta hai jise woh "protect" karta hai.
False — mutex khud se kuch protect nahi karta; yeh tabhi kaam karta hai jab har thread us variable ko touch karne se pehle same mutex lock karne par agree kare. Ek access bhool gaye toh race wapas aa jaati hai. Dekho std::atomic and lock-free programming.
Ek mutex lock karna guarantee karta hai ki tumhara code correct hai.
False — yeh data races hata deta hai, lekin tumhare paas deadlocks, galat lock ordering, ya kisi path par lock bhoolna abhi bhi ho sakta hai. Correctness tumhari zimmedari hai; mutex sirf access ko serialize karta hai.
std::lock_guard aur std::unique_lock same kaam karte hain same speed par.
False —
lock_guard minimal hai aur thoda sasta hai; unique_lock ek extra "kya main abhi isse hold kar raha hoon?" flag rakhta hai early unlock/relock aur moving support karne ke liye, isliye flexible wala sirf tab use karo jab flexibility chahiye.Ek std::thread object wahi running thread hai.
False — object ek handle hai OS thread ka. Thread expectations se zyada survive kar sakta hai; handle us resource ka malik hai aur use
join() ya detach() ke zariye dispose karna zaroori hai.detach() call karna matlab yeh hai ki thread ka kaam definitely main khatam hone se pehle finish ho jaata hai.
False — ek detached thread independently chalta hai, isliye agar
main pehle return kare toh process exit ho jaata hai aur detached thread kaam ke beech mein bina kisi cleanup ke kill ho sakta hai.Do threads same variable ko sirf padhna (kabhi likhna nahi) ek data race hai.
False — concurrent reads bina kisi writer ke safe hain; race ke liye kam se kam ek writer chahiye. Jaise hi koi thread likhti hai, saari accesses synchronized honi chahiye.
lock_guard ko ek function se return kiya ja sakta hai lock ko caller ko transfer karne ke liye.
False —
lock_guard non-movable aur non-copyable hai, isliye yeh apna scope nahi chod sakta. unique_lock movable hai aur ownership hand off karne ke liye return kiya ja sakta hai. Dekho Move semantics.Agar lock() aur unlock() ke beech ka code throw kare, toh RAII phir bhi lock release kar deta hai.
True — yahi poora point hai: stack unwinding guard ka destructor chalata hai, jo unlock karta hai, chahe exception aaye ya early
return.Error dhundho
std::lock_guard lk(mtx); lk.unlock(); heavy_work(); — doosron ko unblock karne ke liye early release karna.
lock_guard ka koi unlock() member nahi hai — yeh compile nahi hoga. Early release ke liye tumhe std::unique_lock use karna hoga, jiska unlock() bilkul isi case ke liye exist karta hai.Thread 1 pehle a phir b lock karta hai; thread 2 pehle b phir a lock karta hai.
Classic deadlock: har ek ek mutex hold karta hai aur doosre ka forever wait karta hai. Fix karo consistent global lock order se, ya
std::lock(a,b) / std::scoped_lock(a,b) se. Dekho Deadlock and lock ordering.std::thread t(work); /* ... */ aur function bina t.join() ke return ho jaata hai.
Ek abhi bhi joinable thread jo scope exit par destroy ho,
std::terminate() call karta hai, poore program ko maar deta hai. Pehle join() ya detach() karo (ya std::jthread use karo).std::thread t2 = t1; same kaam do handles par chalane ke liye.
Ek thread ek unique resource hai aur move-only hai, isliye copy-assignment compile nahi hogi.
std::thread t2 = std::move(t1); use karo — lekin phir t1 kisi bhi thread ka malik nahi rahega.Sirf shared counter par write ko guard karna jabki doosre threads use unlocked read karte hain.
Phir bhi ek data race hai — unlocked reads ek locked write ke saath concurrently chalte hain. Shared data tak har access, reads bhi shaamil hain, same mutex leni chahiye.
std::mutex m; std::lock_guard lk1(m); std::lock_guard lk2(m); ek hi thread mein.
Ek plain
std::mutex non-recursive hai: ek hi thread mein isse do baar lock karna us thread ko khud apne hi against deadlock kar deta hai. std::recursive_mutex sirf tab use karo jab re-entrant locking sachchi zaroorat ho (usually ek design smell hai).cv.wait(lk, pred) use karna jahan lk ek std::lock_guard hai.
Compile nahi hoga —
condition_variable::wait ko ek std::unique_lock chahiye kyunki use soते waqt unlock aur wakeup par re-lock karna hota hai, jo lock_guard nahi kar sakta. Dekho std::condition_variable.Ek mutex lock karna, phir critical section ke andar ek aisa function call karna jo same mutex lock karta hai.
Self-deadlock (same non-recursive mutex, same thread). Nested call us lock ka wait karte hue block ho jaata hai jo uski khud ki thread pehle se hold kar rahi hai aur kabhi release nahi karegi.
Why questions
++counter threads ke across unsafe kyun hai chahe yeh C++ ki "ek line" ho?
Source ki ek line teen machine steps hain — read, increment, write — aur do threads un steps ko is tarah interleave kar sakti hain ki ek increment kho jaata hai. Source lines ki atomicity ek illusion hai.
RAII (lock_guard) un deadlocks ko kyun rokta hai jo manual unlock() invite karta hai?
Ek destructor har scope exit par chalta hai — normal, early
return, break, ya exception — isliye unlock kabhi skip nahi ho sakta, jabki ek hand-written unlock() aisi code ke baad baitha hai jo usse jump past kar sakti hai.Lock ko shortest possible time ke liye kyun hold karo?
Jab tak tum hold karte ho, har doosri thread jo woh mutex chahti hai woh block hai, tumhare peeche serialize ho rahi hai. Lambe critical sections us parallelism ko throw away kar dete hain jo concurrency laane ka maksad tha.
Ek data race "undefined behavior" kyun hai na ki sirf "ek galat number"?
C++ memory model unsynchronized concurrent access ko bilkul koi meaning nahi deta, isliye compiler reorder, cache, ya optimize kar sakta hai jaise yeh hua hi nahi — program literally kuch bhi kar sakta hai. Dekho Undefined behavior in C++.
std::lock(la, lb) us deadlock ko kyun avoid karta hai jo unhe order mein lock karna nahi karta?
Yeh ek lock-and-back-off algorithm use karta hai jo saare mutexes ek saath acquire karta hai ya kuch bhi nahi, isliye yeh kabhi ek hold karte hue doosre ka wait nahi karta — circular-wait condition ko remove karta hai. Dekho Deadlock and lock ordering.
std::thread move-only kyun hai instead of copyable?
Yeh exactly ek underlying OS thread ka malik hai — ek unique, non-duplicable resource. Copying ka matlab hoga ek thread ke do malik, jo meaningless hai, isliye sirf ownership transfer (move) allowed hai. Dekho Move semantics.
Ek simple shared counter ke liye std::atomic<int> ko mutex ke upar kyun prefer karein?
Ek single primitive ke liye, ek lock-free atomic increment mutex ke overhead aur blocking se bachata hai jabki race-free bhi rehta hai — mutex overkill hai. Dekho std::atomic and lock-free programming.
unique_lock ko early release karna (lk.unlock()) heavy, lock-free work se pehle kyun help karta hai?
Heavy work shared state touch nahi karta, isliye lock ko uske through hold karna doosri threads ko bekar rokta. Pehle unlock karne se woh parallel mein proceed kar sakti hain.
Edge cases
Kya hoga agar tum join() karo ek aisi thread ko jo already joined hai ya detach ho chuki hai?
Undefined behavior / ek thrown exception, kyunki handle ab koi joinable thread ka malik nahi.
join() call karne se pehle hamesha t.joinable() check karo ya state track karo.Kya do alag mutexes kabhi deadlock cause kar sakte hain?
Haan — deadlock ordering ke baare mein hai, identity ke baare mein nahi. Agar do threads do alag mutexes ko opposite orders mein acquire karein, toh woh deadlock ho jaati hain. Dekho Deadlock and lock ordering.
Kya ek mutex ko ek thread mein lock karna aur doosri thread se unlock karna safe hai?
Nahi — ek
std::mutex ko usi same thread se unlock kiya jaana chahiye jisne lock kiya tha; aisa karna otherwise undefined behavior hai. (Isliye bhi tum ek raw lock_guard threads ke across hand nahi kar sakte.)Kya hoga agar main return kare jabki ek detached thread abhi bhi ek global mein write kar rahi hai?
Process tear down ho jaata hai; detached thread aisi memory access kar rahi ho sakti hai jo destroy ho rahi hai → undefined behavior. Sirf unhi threads ko detach karo jinki lifetime safely end hone ki tumhe certainty ho.
Kya ek empty (default-constructed) std::thread ko join() ki zaroorat hai?
Nahi — yeh koi thread ka malik nahi,
joinable() false hai, aur iska destructor harmless hai. Sirf ek joinable thread ko join()/detach() chahiye.std::thread ko move karne ke baad uski state kya hoti hai?
Woh non-joinable ho jaata hai (kuch bhi own nahi karta), isliye use koi
join() ki zaroorat nahi, aur destination ab thread ka malik hai aur use dispose karna hoga. Dekho Move semantics.Zero threads, ek thread — kya single-threaded program ke liye bhi mutex chahiye?
Nahi — koi concurrency nahi toh koi race nahi, isliye locking pure overhead hai. Mutexes tabhi matter karte hain jab memory genuinely threads ke across shared ho.
Recall Jaane se pehle ek one-line self-test
Agar tum apne code mein har shared access ke liye "kaun sa mutex is variable ko protect karta hai, kaun lock karta hai, aur kab release hota hai?" aur har std::thread ke liye "kya yeh thread joined hai, detached hai, ya moved-from hai?" answer kar sako — toh tumne is poore page ko internalize kar liya hai.
Connections
- RAII and resource management — destructor-based unlock manual unlock se behtar kyun hai
- Deadlock and lock ordering — "Spot the error" mein ordering traps
- std::condition_variable —
unique_lockkyun,lock_guardkyun nahi - std::atomic and lock-free programming — simple counters ke liye mutex-free alternative
- Undefined behavior in C++ — "data race" ka asal matlab
- Move semantics —
std::threadaurunique_lockmove-only kyun hain