在傳統的UNIX進程模型中,每個進程只有一個控制線程。從概念上講,這與基于線程的模型中只包含一個線程是相同的。在POSIX線程(pthread)的情況下,程序開始運行時,它也是以單進程中的單個控制線程啟動的,在創建多個控制線程以前,程序的行為與傳統的進程并沒有什么區別。新增的線程可以通過調用pthread_create函數創建。
#include <pthread.h>int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);返回值:若成功則返回0,否則返回錯誤編號
當pthread_create成功返回時,由tidp指向的內存單元被設置為新創建的線程的線程ID。attr參數用于定制各種不同的線程屬性。線程屬性在以后介紹,眼下暫時把它設置為NULL,創建默認屬性的線程。
新創建的線程從start_rtn函數的地址開始運行,該函數只有一個無類型指針參數arg,如果需要向start_rtn函數傳遞的參數不止一個,那么需要把這些參數放到一個結構中,然后把這個結構的地址作為arg參數傳入。
線程創建時并不能保證哪個線程會先運行:是新創建的線程還是調用線程。新創建的線程可以訪問進程的地址空間,并且繼承調用線程的浮點環境和信號屏蔽字,但是該線程的未決信號集被清除。
注意pthread函數在調用失敗時通常會返回錯誤碼,它們并不像其他的POSIX函數一樣設置errno。每個線程都提供errno的副本,這只是為了與使用errno的現有函數兼容。在線程中,從函數中返回錯誤碼更為清晰整潔,不需要依賴那些隨著函數執行不斷變化的全局狀態,因而可以把錯誤的范圍限制在引起出錯的函數中。
實例
雖然沒有可移植的方法打印線程ID,但是可以寫一個小的測試程序來完成這個任務,以便更深入地了解線程是如何工作的。程序清單11-1中創建了一個線程并且打印進程ID、新線程的線程ID以及初始線程的線程ID。
程序清單11-1 打印線程ID
#include "apue.h"#include <pthread.h>pthread_t ntid;void PRintids(const char *s){ pid_t pid; pthread_t tid; pid = getpid(); tid = pthread_self(); printf("%s pid %u tid %u (0x%x) /n", s, (unsigned int)pid, (unsigned int)tid, (unsigned int)tid);}void *thr_fn(void *arg){ printids("new thread : "); return((void *)0);}intmain(void){ int err; err = pthread_create(&ntid, NULL, thr_fn, NULL); if(err != 0) err_quit("can't create thread: %s/n", strerror(err)); printids("main thread: "); sleep(1); exit(0);}
編譯上面程序過程中遇到了undefined reference to ‘pthread_create’的問題:
首先,檢查了函數名,沒有寫錯;然后檢查了頭文件<pthread.h>,也包含了。這種摸不著頭腦的問題總是讓人很糾結的......最終在網上找到了出現該問題的原因及其解決方案,參考自:http://blog.csdn.net/llqkk/article/details/2854558
問題原因: pthread 庫不是 linux 系統默認的庫,連接時需要使用靜態庫 libpthread.a,所以在使用pthread_create()創建線程,以及調用 pthread_atfork()函數建立fork處理程序時,需要鏈接該庫。 解決方案: 在編譯中要加 -lpthread參數
問題解決了就OK了嗎?當然不行,由此問題恰好暴露了之前學過的一些知識其實并沒有真正吃透,學的時候理解,遇到問題的時候卻想不起來。其實上面出現的這個問題牽涉到了之前學過的如下兩個知識點:
(1)軟件開發工具GCC http://www.CUOXin.com/nufangrensheng/p/3426405.html。注意其中的GCC鏈接選項部分。
(2)UNIX標準化及實現之POSIX標準可選頭文件 http://www.CUOXin.com/nufangrensheng/p/3496116.html。從中可以看到pthread.h是POSIX標準的可選頭文件,也就是說pthread庫不是Linux系統默認的庫,鏈接時需要使用靜態庫libpthread.a。
更多關于undefined reference to...的問題可參考:http://ticktick.blog.51cto.com/823160/431329
現在我們言歸正傳,從程序清單11-1運行結果來看,兩個線程的進程ID相同,但線程ID不同。不過這不是絕對的,依賴于具體的實現。
這個實例有兩個需要注意的地方:
(1)需要處理主線程和新線程之間的競爭。首先是主線程需要休眠,如果主線程不休眠,它就可能退出,這樣在新線程有機會運行之前整個進程可能就已經終止了。這種行為特征依賴于操作系統中的線程實現和調度算法。
(2)新線程是通過調用pthread_self函數獲取自己的線程ID,而不是從共享內存中讀出或者從線程的啟動例程中以參數的形式接收到?;貞沺thread_create函數,它會通過第一個參數(tidp)返回新建線程的線程ID。在本例中,主線程把新線程ID存放在ntid中,但是新建的線程并不能安全地使用它,如果新線程在主線程調用pthread_create返回之前就運行了,那么新線程看到的是未經初始化的ntid的內容,這個內容并不是正確的線程ID。
本篇博文內容摘自《UNIX環境高級編程》(第二版),僅作個人學習記錄所用。關于本書可參考:http://www.apuebook.com/。
新聞熱點
疑難解答