4.2.5 · Coding › Operating Systems
Ek operating system naye processes banata hai ek existing process ko clone karke, aur phir
(optionally) uska program replace karke. Fresh banane ki jagah clone kyun karte hain? Kyunki
ek fully-formed process setup karna (memory, file descriptors, environment, scheduling
state) bahut bada kaam hai — ek already-existing process ko copy karna aur thoda tweak karna kaafi sasta padta hai. Ye chaar syscalls milke ek assembly line banate hain:
fork() — current process ko parent + child mein clone karo.
exec() — child ka program image ek naye se replace karo.
wait() — parent tab tak pause karta hai jab tak child finish na ho aur uska status collect kare.
exit() — child terminate hota hai aur ek status code wapas deta hai .
Ye fork-then-exec split hi asli Unix design idea hai: "naya process banao" ko
"naya program chalao" se alag karna.
fork() : ek naya process (the child ) banata hai jo calling process (the parent ) ka
almost-exact duplicate hota hai. Do baar return karta hai — ek baar har process mein.
exec() family (execl, execvp, ...): current process ki memory image ko ek naye
program se overwrite kar deta hai. Success par kabhi return nahi karta (wapas aane ke liye purana code raha hi nahi).
wait() / waitpid() : parent ko tab tak suspend karta hai jab tak ek child ka state
change na ho (usually terminate), aur child ka exit status retrieve karta hai. Zombies se bachata hai.
exit(status) : calling process ko khatam karta hai, buffers flush karta hai, aur
status ke low 8 bits store karta hai taaki parent padh sake.
Intuition Ek call do values kyun return karti hai?
fork() se pehle, ek hi process pid = fork(); line execute kar rahi hoti hai. fork() ke
baad, do processes hoti hain, dono usi call se return karne wali hoti hain. Har ek ko
ek alag return value milti hai taaki woh bata sake ki woh kaun hai. Ye thoda weird lagta hai kyunki hum expect karte hain
"ek call → ek return," lekin yahan call literally execution ki duniya ko split kar deti hai.
Resource
fork() ke baad
Memory (code/data/heap/stack)
Logically copied (practically Copy-on-Write )
Open file descriptors
Shared (same underlying file table entry, shared offset)
PID
Different (child ko naya milta hai)
Pending signals
Nahi milte (cleared)
CPU registers / program counter
Copy hote hain → dono same instruction par resume karte hain
Intuition Copy-on-Write (COW) — fork fast kyun hai
Gigabytes memory copy karna sirf isliye ki turant exec() call ho (aur sab uda diya jaaye) bahut
wasteful hoga. Isliye kernel shared pages ko read-only mark karta hai aur tab hi private
copy of a page banata hai jab koi process uspe write kare . Tum sirf usi copying ka cost dete ho jo actually change hoti hai . Isliye fork() bade processes ke liye bhi sasta hai.
exec() success par return kyun nahi karta?
exec() calling process ki memory ko naye program se overwrite kar deta hai. exec() ke
baad wali instruction ab exist nahi karti — woh purani image ke baaki hisse ke saath mita di gayi. Isliye
control "wapas aata hai" naye program ka main() start karke . Sirf tab tum exec() ke baad wala code
chalte dekhte ho jab exec fail ho jaaye (e.g. file not found), isliye agli line hamesha ek error handler hoti hai.
execlp ( "ls" , "ls" , "-l" , NULL ); // try to become 'ls'
perror ( "exec failed" ); // ONLY reached if exec() failed
exit ( 1 );
Intuition Parent ko wait kyun karna padta hai?
Jab child exit() call karta hai, kernel use poora delete nahi kar sakta abhi — usse ek chota sa
record (PID + exit status) rakhna padta hai taaki parent baad mein pooch sake "mera child kaise gaya?". Ek finished
child jiska status collect nahi hua woh zombie hai. wait() parent ka woh record padhna hai, jisse kernel use finally reap kar sakta hai. Agar parent pehle mar jaaye, toh uske orphans ko
init/PID 1 ke paas re-parent kar diya jaata hai jo unhe reap karta hai.
Worked example Ek shell-jaisi program se command chalao
pid_t pid = fork (); // 1. split
if (pid < 0 ) { // 2. fork failed
perror ( "fork" ); exit ( 1 );
} else if (pid == 0 ) { // 3. CHILD branch
execlp ( "ls" , "ls" , "-l" , NULL );
perror ( "exec" ); // only if exec failed
exit ( 127 );
} else { // 4. PARENT branch
int status;
waitpid (pid, & status, 0 ); // block until child done
if ( WIFEXITED (status))
printf ( "child exited %d\n " , WEXITSTATUS (status));
}
Step 1 pehle kyun? Worker create karna zaroori hai pehle, uske baad decide karo ki har side kya kare.
Child ke liye pid == 0 check kyun? Yahi fork ka contract hai — sirf child ko 0 milta hai.
exec ke baad exit(127) kyun? Shell convention: 127 = "command not found".
Parent waitpid(pid,...) kyun karta hai? Us specific child ko reap karne aur uska
status padhne ke liye, zombie se bachne ke liye.
Worked example Fork chain mein kitne processes bante hain yeh count karo
fork ();
fork ();
fork ();
printf ( "hi \n " ); // printed how many times?
Har fork() processes ki sankhya double kar deta hai. 1 se shuru karke:
1 fork 2 fork 4 fork 8
Isliye "hi" 2 3 = 8 baar print hota hai.
Doubling kyun? Parent aur child dono har fork() ke neeche wali lines execute karte rehte hain,
aur phir dono agla fork() hit karte hain.
General rule: n consecutive fork() calls → 2 n processes.
Worked example Parent/child output ordering non-deterministic kyun hota hai
if ( fork () == 0 ) printf ( "child \n " );
else printf ( "parent \n " );
Fork ke baad, do independent processes runnable hain. Scheduler kisi ko bhi pehle chala sakta hai,
isliye output order guaranteed nahi hai. "Child finish ho phir parent print kare" enforce karne ke liye,
parent ko wait() karna padega.
Ye kyun matter karta hai: explicit sync ke bina processes ke beech timing kabhi assume mat karo.
main() ke top se continue karta hai."
Sahi kyun lagta hai: exec() sach mein ek program ko uske main se start karta hai, isliye log
fork aur exec ko mix kar dete hain. Reality: plain fork() child ko usi instruction par resume karata hai
(right after fork()), same code ke saath. Woh main() se tabhi restart karta hai jab tum phir
exec() call karo. Fix: yaad rakho fork = yahan clone karo , exec = naya program .
exec() naye program ko ek naye child process mein chalata hai."
Sahi kyun lagta hai: hum "naya program" ko "naya process" se associate karte hain. Reality:
exec() current process ko replace karta hai — same PID, same parent. Isliye hum usually
pehle fork() karte hain, phir child mein exec() karte hain, taaki parent survive kare. Fix: exec =
body transplant, na ki birth.
wait() ki zarurat nahi; child khud clean up ho jaata hai."
Sahi kyun lagta hai: exit() memory free karta hai, isliye woh gone lagta hai. Reality: exit
status ek zombie ki tarah lingering rehta hai jab tak parent reap nahi karta. Long-running parents jo
kabhi wait nahi karte woh PID table entries leak karte hain. Fix: hamesha wait()/waitpid() karo, ya
SIGCHLD ko appropriate tarike se ignore karo.
exit(256) parent ko 256 return karta hai."
Sahi kyun lagta hai: tumne literally 256 likha. Reality: sirf low 8 bits
bachte hain, isliye parent dekhta hai 256 & 0xFF = 0. Fix: exit codes 0..255 mein rakho.
fork() kaun si teen categories ki values return kar sakta hai aur kisko?0 child ko, child ka PID (>0) parent ko, aur -1 failure par.
Child ko fork() se apna PID milne ki jagah 0 kyun milta hai? Child apna PID getpid() se already le sakta hai; 0 ek free unambiguous "tum child ho" flag hai, aur parent ko actual PID ki zyada zarurat hoti hai.
Copy-on-Write kya hai aur ye fork() ko sasta kyun banata hai? Pages read-only share hote hain aur sirf write hone par copy hote hain, isliye tum sirf usi memory ka cost dete ho jo actually modify hoti hai.
Ek successful exec() kabhi return kyun nahi karta? Woh calling process ki memory image overwrite kar deta hai, isliye exec() ke baad wali instruction exist nahi karti; control naye program ke main ko jaata hai.
fork() ke baad, open file descriptors shared hote hain ya copied?Shared — dono processes same open file table entry ko refer karte hain (aur file offset share karte hain).
Zombie process kya hoti hai? Ek child jo terminate ho chuka ho lekin jiska exit status parent ne wait() ke zariye abhi collect nahi kiya.
Jab parent mar jaata hai toh orphaned children ka kya hota hai? Unhe init (PID 1) ke paas re-parent kar diya jaata hai, jo unhe reap karta hai.
3 consecutive fork() calls ke baad kitne processes exist karte hain? 2 3 = 8 .
WEXITSTATUS(status) tumhe kya deta hai?Woh value ke low 8 bits jo child ne exit() ko pass kiye the.
Shell ko exec() se pehle fork() kyun karna padta hai? Taaki parent (shell) survive kare; exec() warna shell ko hi naye program se replace kar deta.
Fork fail hone ka return value pattern kya hai aur use kaise detect karo? fork() -1 return karta hai aur koi child create nahi hota; if (pid < 0) check karo.
Recall Feynman: ek 12-saal ke bacche ko samjhao
Socho tumhare paas ek robot hai jo pehle se kaam karna jaanta hai. Bilkul naaya robot banana
bahut mehnat ka kaam hai, isliye tum ek "copy" button (fork) dabaate ho aur ab do
identical robots hain. Ek robot "boss" hai aur ek "helper" — woh bata sakte hain ki woh kaun hain kyunki copy button boss ko helper ka naam wali sticky note deta hai, aur helper ko blank note milti hai (woh 0). Helper phir ek naya instruction manual padh sakta hai
aur bilkul alag robot ban sakta hai (exec) — same body, naya brain. Jab helper apna
kaam khatam karta hai toh woh ek chota flag uthata hai jisme likha hota hai "kaam hua, yeh mera score hai" (exit). Boss us flag ka intezaar karta hai (wait), score padhta hai, aur tabhi helper ko hatane deta hai — warna khatam hua helper wahan frozen "zombie" banke khada rehta hai.
F-E-W-E : F ork copy karta hai, E xec replace karta hai, W ait collect karta hai, E xit report karta hai.
"Forked Eggs, Waiter Exits " — cook fork karta hai (split), recipe exec ute karta hai, cook
uske done hone ka wait karta hai, dish ek rating ke saath exit karti hai.
Processes vs Threads — threads by default memory share karte hain; fork alag (COW) memory deta hai.
Process Control Block (PCB) — fork() ke dauran kya copy/create hota hai.
Zombie and Orphan Processes — wait() missing hone ka seedha consequence.
Inter-Process Communication — fork ke baad shared FDs, pipes enable karte hain.
Copy-on-Write Memory — saste fork() ke peeche ka optimization.
The Shell — fork+exec+wait hi shell ka commands chalane ka dil hai.
Signals (SIGCHLD) — children reap karne ke liye blocking wait() ka alternative.