Thread 執行緒管理
## Thread(執行緒)的基本觀念
**執行緒(Thread)** 是程序(Process)中的一條執行路徑。
同一個程序可以包含多個執行緒,這些執行緒通常:
- 共用同一份程式碼、全域變數、Heap 記憶體與開啟的檔案
- 各自擁有自己的 Stack、暫存器與程式計數器
- 可以由作業系統排程,在多核心 CPU 上真正平行執行
- 因為共享記憶體,溝通方便,但也容易產生 **Race Condition(競爭條件)**
例如:
```text
Process
├── Thread 1
├── Thread 2
└── Thread 3
```
執行緒切換通常比程序切換便宜,但執行緒之間若同時修改共享資料,就需要使用 Mutex、Semaphore 或其他同步機制。
---
## C 中常見的執行緒控制介面
在 Linux/Unix 系統上,C 通常使用 POSIX Thread,也就是 `pthread` 函式庫。這些函式多半是對作業系統底層 System Call 的包裝。
### 1. 建立執行緒:`pthread_create`
```c
pthread_create(...)
```
建立一個新的執行緒,讓它從指定的函式開始執行。
在 Linux 中,底層通常會透過 `clone()` 等機制建立與原程序共享資源的執行緒。
---
### 2. 等待執行緒結束:`pthread_join`
```c
pthread_join(thread, NULL);
```
讓目前執行緒等待另一個執行緒結束。
這和程序中的 `wait()` 類似,可以避免主執行緒太早結束。
---
### 3. 結束執行緒:`pthread_exit`
```c
pthread_exit(NULL);
```
結束目前執行緒。若執行緒函式直接 `return`,通常也會達到類似效果。
---
### 4. 暫停執行:`sleep`、`nanosleep`
```c
sleep(1);
```
讓執行緒暫停指定秒數。執行緒進入睡眠狀態期間,CPU 可以排程其他執行緒執行。
更精確的介面是:
```c
nanosleep(...)
```
其底層通常會使用 Linux 的睡眠相關系統呼叫。
---
### 5. 主動讓出 CPU:`sched_yield`
```c
sched_yield();
```
提示排程器目前執行緒暫時讓出 CPU,讓其他可執行緒有機會執行。
---
### 6. 執行緒同步:Mutex、Semaphore、Condition Variable
常見函式包括:
```c
pthread_mutex_lock()
pthread_mutex_unlock()
sem_wait()
sem_post()
pthread_cond_wait()
pthread_cond_signal()
```
在 Linux 中,Mutex 等同步機制底層常使用 `futex` 系統呼叫,以避免多個執行緒同時修改共享資料。
---
## 簡單範例:建立兩個執行緒並等待它們結束
以下範例建立兩個執行緒,每個執行緒印出訊息三次,並使用 `sleep()` 模擬工作。
```c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
void *worker(void *arg)
{
int id = *(int *)arg;
for (int i = 1; i <= 3; i++) {
printf("Thread %d: working... %d\n", id, i);
sleep(1);
}
printf("Thread %d: finished\n", id);
return NULL;
}
int main(void)
{
pthread_t thread1, thread2;
int id1 = 1;
int id2 = 2;
// 建立兩個執行緒
if (pthread_create(&thread1, NULL, worker, &id1) != 0) {
perror("pthread_create");
return EXIT_FAILURE;
}
if (pthread_create(&thread2, NULL, worker, &id2) != 0) {
perror("pthread_create");
return EXIT_FAILURE;
}
// 等待兩個執行緒完成
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
printf("Main thread: all workers finished\n");
return 0;
}
```
### 編譯方式
```bash
gcc thread_example.c -o thread_example -pthread
```
執行:
```bash
./thread_example
```
可能的輸出如下:
```text
Thread 1: working... 1
Thread 2: working... 1
Thread 1: working... 2
Thread 2: working... 2
Thread 1: working... 3
Thread 2: working... 3
Thread 1: finished
Thread 2: finished
Main thread: all workers finished
```
實際輸出順序可能不同,因為執行緒的執行順序由作業系統排程器決定。
---
## 需要注意的重點
1. `pthread_create()` 成功後,新的執行緒會和主執行緒同時執行。
2. 多個執行緒共用全域變數與 Heap 資料,因此修改共享資料時需要同步。
3. `pthread_join()` 能確保主執行緒等待工作執行緒完成。
4. `pthread` 函式是函式庫 API,不一定直接等同於一個 System Call;它們通常會在底層使用 Linux 的 `clone`、`futex`、`nanosleep` 等系統呼叫。
5. 執行緒適合用於平行處理、背景工作、網路服務與提升 I/O 等待期間的 CPU 使用率。
相關學習地圖、教學課程
C 語言,系統程式