並行程式設計練習題 (Practice - Concurrent Programming)


Question 1 - 三種並行途徑 [recall]

現代 OS 提供三種建構並行程式的基本途徑:Processes、I/O multiplexing、Threads。
請分別說明:各由誰負責排程?邏輯流之間的位址空間是共享還是私有?為何說 Threads 是「混合體」?


Question 2 - Thread Context 與共享 [recall]

同一個 process 內的多個 threads,哪些東西屬於各 thread 私有的 thread context?哪些是所有 threads 共享的?


Question 3 - Thread 終止方式 [recall]

列出 thread 終止的四種方式,並說明:main thread 呼叫 pthread_exit 與呼叫 exit 的行為差異。


Question 4 - select 的語意與副作用 [recall]

使用 select 撰寫 I/O multiplexing 伺服器時:
(a) 「描述子 k ready for reading」的精確定義是什麼?
(b) 為何每輪迴圈都必須先執行 ready_set = read_set; 再呼叫 select?


Question 5 - Shared Variable 的判定 [recall]

CSAPP 對「shared variable」給出精確定義。請寫出該定義,並說明 global、local static、local automatic 三種變數在 run time 各有幾份 instance。


Question 6 - P/V 操作與 Semaphore Invariant [recall]

說明 Dijkstra semaphore 的 P(s) 與 V(s) 操作語意(含 s = 0 時 P 的行為、V 重啟等待者的規則),並寫出 semaphore invariant。


Question 7 - Readers-Writers 與 Starvation [recall]

Readers-writers problem 有 first(偏袒 readers)與 second(偏袒 writers)兩種變體。請說明兩者的規則差異,以及為何說「兩種正確解都可能導致 starvation」。


Question 8 - 四類 Thread-Unsafe Functions [recall]

列出四類 thread-unsafe functions,各舉一例,並指出哪一類「只能改寫、無法用鎖補救」。


Question 9 - Reentrant vs Thread-Safe [recall]

說明 reentrant function 的定義、它與 thread-safe functions 的集合關係,以及 explicitly reentrant 與 implicitly reentrant 的差別。


Question 10 - connfd Refcount 追蹤 [application]

Process-based echo server 中(Figure 12.5),listenfd = 3、accept 回傳 connfd = 4。
追蹤 connfd 對應 file table entry 的 reference count:從 accept 回傳、fork、parent Close(connfd)、到 child 服務完關閉,各是多少?若 parent 忘了 Close(connfd) 會發生什麼事?


Question 11 - Speedup 與 Efficiency 計算 [application]

某平行程式循序版在單核執行時間 T1=16 秒;平行版在 4 核執行 T4=8 秒、在 8 核執行 T8=4 秒。
計算 S4,E4,S8,E8,並說明 absolute speedup 與 relative speedup 哪個較能真實反映平行化效益。


Question 12 - Sbuf Semaphore 初值與 n=1 特例 [application]

Producer-consumer 的 sbuf_t 使用三個 semaphores:mutexslotsitems
(a) 三者的初始值各是多少?各扮演什麼角色?
(b) 若 buffer 只有 1 個 slot(n = 1),即使有多個 producers 與 consumers,mutex 是否仍必要?為什麼?


Question 13 - cnt++ 的 Interleaving 分析 [analysis]

兩個 threads 各執行 cnt++(共享 volatile long cnt,初值 0)一次。cnt++ 被編譯為三步:Li(load 到 %rdxi)、Ui(加 1)、Si(寫回)。
考慮執行順序 L1,L2,U2,S2,U1,S1:逐步追蹤 %rdx1、%rdx2 與 cnt 的值,判斷最終結果是否正確,並給出判斷任意 interleaving 正確與否的一般準則。


Question 14 - Deadlock 的 Progress Graph 分析 [analysis]

兩個 threads 使用兩個初始值皆為 1 的 mutexes s、t:

/* Thread 1 */          /* Thread 2 */
P(s); P(t);             P(t); P(s);
/* critical section */  /* critical section */
V(s); V(t);             V(t); V(s);

用 progress graph 的觀點解釋:為何這段程式可能 deadlock 卻又不一定每次都 deadlock?應如何修正?