線程技術最早於 60 年代提出,80 年代中期才真正應用於作業系統,Solaris 是先驅。傳統 Unix 僅允許一個進程擁有一條線程,故多線程意味著多進程。現今 Windows/NT、Linux 等主流作業系統皆支援多線程。
為何有進程還需線程?多線程有何優勢?何時該選用?首先必須釐清這些問題。
Linux 下啟動新進程需分配獨立位址空間、建立眾多資料表維護代碼段/堆疊段/資料段,屬「昂貴」的多任務方式。同一進程內的多線程共享位址空間與大部分資料,啟動線程的空間遠小於進程,線程切換時間也遠小於進程切換。統計顯示,進程開銷約為線程的 30 倍(具體系統數值可能差異較大)。
進程間擁有獨立資料空間,傳遞資料只能透過進程間通訊(IPC),耗時且不便。線程共享資料空間,一個線程的資料可直接供其他線程使用,快捷方便。但共享也帶來同步問題:變數不可同時被兩線程修改,static 變數更可能導致災難性後果,這正是編寫多線程程式時最需注意之處。
Linux 多線程遵循 POSIX 執行緒介面(pthread)。編寫需包含 pthread.h,連結時需 -lpthread。Linux 的 pthread 透過系統呼叫 clone() 實現(類似 fork,為 Linux 專有)。以下展示最簡單的多線程程式 example1.c:
/* example1.c */
#include <stdio.h>
#include <pthread.h>
void thread(void) {
int i;
for (i = 0; i < 3; i++)
printf("This is a pthread.\n");
}
int main(void) {
pthread_t id;
int i, ret;
ret = pthread_create(&id, NULL, (void *)thread, NULL);
if (ret != 0) {
printf("Create pthread error!\n");
exit(1);
}
for (i = 0; i < 3; i++)
printf("This is the main process.\n");
pthread_join(id, NULL);
return 0;
}
編譯:gcc example1.c -lpthread -o example1
運行結果示例(兩次運行順序不同,體現線程搶佔 CPU):
This is the main process. This is a pthread. This is the main process. This is the main process. This is a pthread. This is a pthread.
This is a pthread. This is the main process. This is a pthread. This is the main process. This is a pthread. This is the main process.
關鍵函數:pthread_create 建立線程,pthread_join 等待線程結束,pthread_t 為線程識別碼型別。