pthreads 與標準執行緒(pthreads / standard threads)
/ pthreads -> 'PEE-threads'; POSIX -> 'PAH-ziks' /
一旦你理解了執行緒是什麼,你就需要一個具體的方式去要一條來。在類 Unix 系統上,經典的方式是 pthreads——POSIX 執行緒,一套建立與管理執行緒的標準函式庫。你最先遇到的兩個是 pthread_create(),它啟動一條新執行緒去跑你指定的函式;以及 pthread_join(),它在你繼續之前等那條執行緒結束。光憑這兩個,你就能衍生一名工人,稍後再收回它的結果。
用白話的步驟看它的樣子。你寫一個讓新執行緒去跑的函式,簽章是固定的:它收一個 void * 引數(這樣你能透過指標傳任何資料給它),回傳一個 void *(這樣它能把結果交回來)。你呼叫 pthread_create(),傳給它一個指向 pthread_t 變數的指標(它會填入,作為這條新執行緒的把手)、要跑的函式、以及要傳入的引數。新執行緒立刻開始跑那個函式,與你的程式碼平行進行。稍後你對那個把手呼叫 pthread_join();它會阻塞,直到那條執行緒返回,並把該執行緒的回傳值交還給你。C 在 C11 加入了自己的可攜版本(threads.h 標頭,含 thrd_create() 與 thrd_join()),C++11 加了 std::thread,但在 Linux 與 macOS 上,這些底層常是建在 pthreads 之上。
這為何重要:pthreads 是 Unix 上 C 語言執行緒的通用語。名字笨重、錯誤處理也得手動(多數函式成功回傳 0,否則回傳一個錯誤碼),但模型小而清楚:建立、跑一個函式、join。本欄位中所有更難的東西——上鎖、信號通知、原子操作——都建在「建立共享記憶體的執行緒」這個基本能力之上。先把建立與 join 練熟;危害來自這些執行緒一旦跑起來之後做了什麼。
一個最小的建立與 join,為清楚起見略去錯誤檢查:pthread_t t; pthread_create(&t, NULL, worker, arg); ... pthread_join(t, NULL); 其中 worker 的簽章為 void *worker(void *arg)。編譯時用 gcc main.c -pthread。
建立一條執行緒去跑 worker(),做別的事,然後 join 等它結束。
你必須以 -pthread 連結(不是只引入標頭),否則程式可能編得過卻行為錯誤。而且 pthread 函式直接回傳錯誤碼——它們不設定 errno——所以偵測失敗要看回傳值,而非 errno。