# 多線程編程:復習題
> 原文:<https://github.com/angrave/SystemProgramming/wiki/Multi-threaded-Programming%3A-Review-Questions>
> 警告 - 問題編號可能會有變化
## Q1
以下代碼是否是線程安全的?重新設計以下代碼是線程安全的。提示:如果消息內存對每個調用都是唯一的,則不需要互斥鎖。
```c
static char message[20];
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void format(int v) {
pthread_mutex_lock(&mutex);
sprintf(message, ":%d:" ,v);
pthread_mutex_unlock(&mutex);
return message;
}
```
## Q2
以下哪一項不會導致進程退出?
* 從最后一個運行線程中的 pthread 的啟動函數返回。
* 從 main 返回的原始線程。
* 任何導致分段錯誤的線程。
* 任何調用`exit`的線程。
* 在主線程中調用`pthread_exit`,其他線程仍在運行。
## Q3
寫下將由以下程序打印的“W”字符數的數學表達式。假設 a,b,c,d 是小的正整數。你的答案可能會使用'min'函數返回其最低值的參數。
```c
unsigned int a=...,b=...,c=...,d=...;
void* func(void* ptr) {
char m = * (char*)ptr;
if(m == 'P') sem_post(s);
if(m == 'W') sem_wait(s);
putchar(m);
return NULL;
}
int main(int argv, char** argc) {
sem_init(s,0, a);
while(b--) pthread_create(&tid, NULL, func, "W");
while(c--) pthread_create(&tid, NULL, func, "P");
while(d--) pthread_create(&tid, NULL, func, "W");
pthread_exit(NULL);
/*Process will finish when all threads have exited */
}
```
## Q4
完成以下代碼。以下代碼應該打印交替`A`和`B`。它代表兩個輪流執行的線程。將條件變量調用添加到`func`,以便等待的線程不需要連續檢查`turn`變量。問:是否需要 pthread_cond_broadcast 或者 pthread_cond_signal 是否足夠?
```c
pthread_cond_t cv = PTHREAD_COND_INITIALIZER;
pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
void* turn;
void* func(void* mesg) {
while(1) {
// Add mutex lock and condition variable calls ...
while(turn == mesg) {
/* poll again ... Change me - This busy loop burns CPU time! */
}
/* Do stuff on this thread */
puts( (char*) mesg);
turn = mesg;
}
return 0;
}
int main(int argc, char** argv){
pthread_t tid1;
pthread_create(&tid1, NULL, func, "A");
func("B"); // no need to create another thread - just use the main thread
return 0;
}
```
## Q5
確定給定代碼中的關鍵部分。添加互斥鎖定以使代碼線程安全。添加條件變量調用,以使`total`永遠不會變為負數或高于 1000.相反,調用應該阻塞,直到可以繼續進行。解釋為什么`pthread_cond_broadcast`是必要的。
```c
int total;
void add(int value) {
if(value < 1) return;
total += value;
}
void sub(int value) {
if(value < 1) return;
total -= value;
}
```
## Q6
非線程安全數據結構具有`size()` `enq`和`deq`方法。使用條件變量和互斥鎖來完成線程安全的阻塞版本。
```c
void enqueue(void* data) {
// should block if the size() would become greater than 256
enq(data);
}
void* dequeue() {
// should block if size() is 0
return deq();
}
```
## Q7
您的啟動使用最新的交通信息提供路徑規劃。您的多付實習生創建了一個非線程安全的數據結構,其中包含兩個函數:`shortest`(使用但不修改圖形)和`set_edge`(修改圖形)。
```c
graph_t* create_graph(char* filename); // called once
// returns a new heap object that is the shortest path from vertex i to j
path_t* shortest(graph_t* graph, int i, int j);
// updates edge from vertex i to j
void set_edge(graph_t* graph, int i, int j, double time);
```
為了提高性能,多個線程必須能夠同時調用`shortest`,但是當`shortest`或`set_edge`內??沒有其他線程執行時,只能通過一個線程修改圖形。
使用互斥鎖和條件變量來實現讀寫器解決方案。不完整的嘗試如下所示。雖然這種嘗試是線程安全的(因此足以用于演示日!),但它不允許多個線程同時計算`shortest`路徑并且沒有足夠的吞吐量。
```c
path_t* shortest_safe(graph_t* graph, int i, int j) {
pthread_mutex_lock(&m);
path_t* path = shortest(graph, i, j);
pthread_mutex_unlock(&m);
return path;
}
void set_edge_safe(graph_t* graph, int i, int j, double dist) {
pthread_mutex_lock(&m);
set_edge(graph, i, j, dist);
pthread_mutex_unlock(&m);
}
```
- UIUC CS241 系統編程中文講義
- 0. 簡介
- #Informal 詞匯表
- #Piazza:何時以及如何尋求幫助
- 編程技巧,第 1 部分
- 系統編程短篇小說和歌曲
- 1.學習 C
- C 編程,第 1 部分:簡介
- C 編程,第 2 部分:文本輸入和輸出
- C 編程,第 3 部分:常見問題
- C 編程,第 4 部分:字符串和結構
- C 編程,第 5 部分:調試
- C 編程,復習題
- 2.進程
- 進程,第 1 部分:簡介
- 分叉,第 1 部分:簡介
- 分叉,第 2 部分:Fork,Exec,等等
- 進程控制,第 1 部分:使用信號等待宏
- 進程復習題
- 3.內存和分配器
- 內存,第 1 部分:堆內存簡介
- 內存,第 2 部分:實現內存分配器
- 內存,第 3 部分:粉碎堆棧示例
- 內存復習題
- 4.介紹 Pthreads
- Pthreads,第 1 部分:簡介
- Pthreads,第 2 部分:實踐中的用法
- Pthreads,第 3 部分:并行問題(獎金)
- Pthread 復習題
- 5.同步
- 同步,第 1 部分:互斥鎖
- 同步,第 2 部分:計算信號量
- 同步,第 3 部分:使用互斥鎖和信號量
- 同步,第 4 部分:臨界區問題
- 同步,第 5 部分:條件變量
- 同步,第 6 部分:實現障礙
- 同步,第 7 部分:讀者編寫器問題
- 同步,第 8 部分:環形緩沖區示例
- 同步復習題
- 6.死鎖
- 死鎖,第 1 部分:資源分配圖
- 死鎖,第 2 部分:死鎖條件
- 死鎖,第 3 部分:餐飲哲學家
- 死鎖復習題
- 7.進程間通信&amp;調度
- 虛擬內存,第 1 部分:虛擬內存簡介
- 管道,第 1 部分:管道介紹
- 管道,第 2 部分:管道編程秘密
- 文件,第 1 部分:使用文件
- 調度,第 1 部分:調度過程
- 調度,第 2 部分:調度過程:算法
- IPC 復習題
- 8.網絡
- POSIX,第 1 部分:錯誤處理
- 網絡,第 1 部分:簡介
- 網絡,第 2 部分:使用 getaddrinfo
- 網絡,第 3 部分:構建一個簡單的 TCP 客戶端
- 網絡,第 4 部分:構建一個簡單的 TCP 服務器
- 網絡,第 5 部分:關閉端口,重用端口和其他技巧
- 網絡,第 6 部分:創建 UDP 服務器
- 網絡,第 7 部分:非阻塞 I O,select()和 epoll
- RPC,第 1 部分:遠程過程調用簡介
- 網絡復習題
- 9.文件系統
- 文件系統,第 1 部分:簡介
- 文件系統,第 2 部分:文件是 inode(其他一切只是數據...)
- 文件系統,第 3 部分:權限
- 文件系統,第 4 部分:使用目錄
- 文件系統,第 5 部分:虛擬文件系統
- 文件系統,第 6 部分:內存映射文件和共享內存
- 文件系統,第 7 部分:可擴展且可靠的文件系統
- 文件系統,第 8 部分:從 Android 設備中刪除預裝的惡意軟件
- 文件系統,第 9 部分:磁盤塊示例
- 文件系統復習題
- 10.信號
- 過程控制,第 1 部分:使用信號等待宏
- 信號,第 2 部分:待處理的信號和信號掩碼
- 信號,第 3 部分:提高信號
- 信號,第 4 部分:信號
- 信號復習題
- 考試練習題
- 考試主題
- C 編程:復習題
- 多線程編程:復習題
- 同步概念:復習題
- 記憶:復習題
- 管道:復習題
- 文件系統:復習題
- 網絡:復習題
- 信號:復習題
- 系統編程笑話