5.2.28 · D5 · HinglishC++ Programming

Question bankstd - promise and std - future

1,350 words6 min read↑ Read in English

5.2.28 · D5 · Coding › C++ Programming › std - promise and std - future

Do words jinhe hum baar baar use karte hain: shared state wo heap-allocated control block hai (value slot, exception slot, ready flag, mutex, condition variable) jise ek promise likhta hai aur ek future padhta hai. "Move-only" ka matlab hai ki object ko std::move se hand over kiya ja sakta hai par copy nahi kiya ja sakta.


True or false — justify

A std::promise<int> can be copied into two threads so both can fulfil it.
False. promise move-only hota hai; copy karne se ek hi shared state ke do writers ban jaate, jo exactly wahi race hai jise ye abstraction rokne ke liye bana hai.
future::get() ko same value dobara padhne ke liye safely do baar call kiya ja sakta hai.
False. get() result ko move out kar deta hai aur future ko invalidate kar deta hai; doosri call future_error(no_state) throw karti hai. Multiple reads ke liye std::shared_future use karo.
Ek hi promise pe prom.get_future() do baar call karna legal hai aur do futures return karta hai.
False. Shared state ka ek hi reading end hota hai; doosri call std::future_error(future_already_retrieved) throw karti hai.
future::wait() value ko get() ki tarah consume kar leta hai.
False. wait() sirf ready hone tak block karta hai aur return karta hai; value shared state mein rehti hai, toh baad mein get() phir bhi kaam karta hai.
Agar aapne kabhi set_value call nahi kiya aur promise destroy ho jaaye, toh get() hamesha ke liye block ho jaata hai.
False. Promise ka destructor ek broken_promise error store karta hai, isliye get() throw karta hai future_error(broken_promise) — ye hang nahi karta.
std::future copyable hai, isliye aap use do consumers ko pass kar sakte ho.
False. future bhi move-only hota hai. Kai readers tak fan-out ke liye ise share() se std::shared_future mein convert karo.
set_value aur set_exception dono ek hi promise pe call ho sakte hain agar aap fallback chahte ho.
False. Shared state one-shot hota hai; doosri set call promise_already_satisfied throw karti hai. Har path pe exactly ek hi outcome choose karo.
Hand-built version mein condition-variable predicate optional hai agar aap sirf ek baar notify karte ho.
False. condition_variable spuriously wake ho sakta hai, aur set, wait shuru hone se pehle bhi ho sakta hai; predicate ready ko dobara check karta hai dono cases cover karne ke liye.
fut.valid() successful get() ke baad true return karta hai.
False. get() future ko invalidate kar deta hai, isliye valid() false ho jaata hai. Ye true tabhi hota hai jab future kisi live shared state se juda ho aur abhi consume na hua ho.

Spot the error

std::thread t(worker, std::move(prom));
auto fut = prom.get_future();
``` ::: Promise **pehle move ho gaya**, isliye local `prom` ke paas koi shared state nahi hai aur `get_future()` throw karta hai. Future **pehle** grab karo, phir move karo.
 
```cpp
std::thread t(worker, prom); // prom is std::promise<int>
``` ::: `promise` non-copyable hai, isliye ye compile nahi hoga (ya ek writer duplicate ho jaata). `std::move(prom)` se wrap karo.
 
```cpp
void worker(std::promise<int> p) { throw std::runtime_error("boom"); }
``` ::: Exception thread function se escape kar jaata hai → `std::terminate`. Ise catch karo aur ship karo: `p.set_exception(std::current_exception())`.
 
```cpp
int x = fut.get();
int y = fut.get(); // read it again
``` ::: Pehle `get()` ne value move out kar li aur future invalidate ho gaya; doosri call `future_error(no_state)` throw karti hai. `x` store karo aur use reuse karo.
 
```cpp
p.set_value(1);
p.set_exception(std::current_exception());
``` ::: Sirf ek hi outcome allowed hai. Doosri call `promise_already_satisfied` throw karti hai. `try/catch` use karo taaki exactly unhi mein se ek chale.
 
```cpp
std::promise<int> prom;
auto fut = prom.get_future();
// ... path where an early 'return' skips set_value ...
``` ::: Early-return path pe promise bina set hue destroy ho jaata hai, isliye waiting `get()` `broken_promise` throw karta hai. Promise ko **har** control-flow path pe fulfil karo.
 
---
 
## Why questions
 
Ek plain [[std - thread|std::thread]] apne creator ko value kyun return nahi kar sakta? ::: `thread` ke callable ka return value discard ho jaata hai; koi built-in channel back nahi hota. `promise`/`future` (ya [[std - async and std - launch|std::async]]) woh channel provide karta hai.
 
Exception ko `std::exception_ptr` ke roop mein kyun transport kiya jaata hai, na ki exception object khud? ::: Type boundary pe unknown hoti hai aur object ko threads ke across move hone ke baad bhi survive karna padta hai; `exception_ptr` ise type-erase aur reference-count karta hai taaki `get()` `rethrow_exception` ke zariye exact original re-throw kar sake. Dekho [[Exception handling in C++]].
 
Producer sirf `ready = true` set karne ke liye [[std - mutex and lock_guard|mutex]] kyun lock karta hai? ::: Ek thread mein `value`/`ready` likhna jabki doosra unhe padh raha ho — ye data race hai (undefined behaviour); mutex aur notify milke woh happens-before ordering establish karte hain jo read ko safe banata hai.
 
`promise`/`future` ko `bool ready` flag wale global variable se zyada kyun prefer karein? ::: Library mutex, condition variable, ready flag **aur** exception transport ko sahi aur portable tarike se package karti hai, hand-rolled race aur missed-wakeup bugs ko khatam karti hai.
 
`get()` value ko copy karne ki bajaye **move** kyun karta hai? ::: Channel one-shot hai aur result ka single owner hota hai, isliye move karna sasta bhi hai aur semantically honest bhi — consume karne ke baad padhne ke liye kuch bachta nahi. Dekho [[Move semantics and std::move]].
 
`set_value` consumer ke `wait` call karne se **pehle** poora kyun run ho sakta hai? ::: Dono threads wall-clock time mein unsynchronized hain; ready flag "already done" capture karta hai taaki `wait(lk, pred)` notify miss karne ki bajaye immediately return kare.
 
---
 
## Edge cases
 
Agar `set_value` ki jagah `set_exception` use hua ho toh `get()` kya karta hai? ::: Stored exception ko **consumer ke** thread mein re-throw karta hai, taaki aap ise wahan handle karo jahan aap wait karte ho, na ki jahan throw hua tha.
 
`get_future()` ke turant baad par kisi bhi `set` se pehle `future::valid()` kya return karta hai? ::: `true` — future ek live shared state se associated hai; `get()` pe sirf tab tak block karta hai jab tak value ya exception na aaye.
 
Agar `set_value` aur promise ka destructor dono run ho jaayein, toh kya destructor `broken_promise` se overwrite karta hai? ::: **Nahi.** Ek baar satisfied hone ke baad, destruction state ke liye ek clean no-op hai; `broken_promise` tabhi store hota hai jab destruction ke waqt state abhi **unsatisfied** ho.
 
Kya promise ko move karna, use naye thread mein fulfil karna, aur original (ab empty) ko scope se bahar jaane dena legal hai? ::: **Haan.** Moved-from promise ke paas koi shared state nahi hota, isliye uski destruction kuch nahi karti; moved-to promise state ko normally own aur fulfil karta hai.
 
Kya hota hai agar `get()` kisi aise `future` pe call ho jo move ho chuka ho? ::: Ye `future_error(no_state)` throw karta hai — moved-from future ka koi association nahi hota. Agar sure nahi ho toh `valid()` se guard karo.
 
Kya `promise<void>` exist kar sakta hai, aur uska `get()` kya return karta hai? ::: **Haan.** `promise<void>`/`future<void>` koi value carry nahi karte — `set_value()` koi argument nahi leta aur `get()` kuch return nahi karta; ye purely "done" signal karne ya exception transport karne ke liye exist karte hain.