1. 程式人生 > >執行緒間無需特別的手段進行通訊,因為執行緒間可以共享資料結構,也就是一個全域性變數可以被兩個執行緒同時使用,不過要注意的是執行緒間需要做好同步。

執行緒間無需特別的手段進行通訊,因為執行緒間可以共享資料結構,也就是一個全域性變數可以被兩個執行緒同時使用,不過要注意的是執行緒間需要做好同步。

     執行緒間無需特別的手段進行通訊,因為執行緒間可以共享資料結構,也就是一個全域性變數可以被兩個執行緒同時使用。不過要注意的是執行緒間需要做好同步,一般用mutex。可以參考一些比較新的UNIX/Linux程式設計的書,都會提到Posix執行緒程式設計,比如《UNIX環境高階程式設計(第二版)》、《UNIX系統程式設計》等等。 linux的訊息屬於IPC,也就是程序間通訊,執行緒用不上。

linux用pthread_kill對執行緒發訊號。 另:windows下不是用post..(你是說PostMessage嗎?)進行執行緒通訊的吧?
windows用PostThreadMessage進行執行緒間通訊,但實際上極少用這種方法。還是利用同步多一些 LINUX下的同步和Windows原理都是一樣的。不過Linux下的singal中斷也很好用。
用好訊號量,共享資源就可以了。 
 使用多執行緒的理由之一是和程序相比,它是一種非常"節儉"的多工操作方式。我們知道,在Linux系統下,啟動一個新的程序必須分配給它獨立的地址空間,建立眾多的資料表來維護它的程式碼段、堆疊段和資料段,這是一種"昂貴"的多工工作方式。而運行於一個程序中的多個執行緒,它們彼此之間使用相同的地址空間,共享大部分資料,啟動一個執行緒所花費的空間遠遠小於啟動一個程序所花費的空間,而且,執行緒間彼此切換所需的時間也遠遠小於程序間切換所需要的時間。

  使用多執行緒的理由之二是執行緒間方便的

通訊機制。對不同程序來說,它們具有獨立的資料空間,要進行資料的傳遞只能通過通訊的方式進行,這種方式不僅費時,而且很不方便。執行緒則不然,由於同一程序下的執行緒之間共享資料空間,所以一個執行緒的資料可以直接為其它執行緒所用,這不僅快捷,而且方便。當然,資料的共享也帶來其他一些問題,有的變數不能同時被兩個執行緒所修改,有的子程式中宣告為static的資料更有可能給多執行緒程式帶來災難性的打擊,這些正是編寫多執行緒程式時最需要注意的地方。
1、簡單的多執行緒程式

   首先在主函式中,我們使用到了兩個函式,pthread_create和pthread_join,並聲明瞭一個pthread_t型的變數。
pthread_t在標頭檔案pthread.h中已經宣告,是執行緒的標示符

   函式pthread_create用來建立一個執行緒,函式原型:

extern int pthread_create __P ((pthread_t *__thread, __const pthread_attr_t *__attr,void *(*__start_routine) (void *), void *__arg));

  第一個引數為指向執行緒識別符號的指標,第二個引數用來設定執行緒屬性,第三個引數是執行緒執行函式的起始地址,最後一個引數是執行函式的引數。若我們的函式thread不需要引數,所以最後一個引數設為空指標。第二個引數我們也設為空指標,這樣將生成預設屬性的執行緒。對執行緒屬性的設定和修改我們將在下一節闡述。當建立執行緒成功時,函式返回0,若不為0則說明建立執行緒失敗,常見的錯誤返回程式碼為EAGAIN和EINVAL。前者表示系統限制建立新的執行緒,例如執行緒數目過多了;後者表示第二個引數代表的執行緒屬性值非法。建立執行緒成功後,新建立的執行緒則執行引數三和引數四確定的函式,原來的執行緒則繼續執行下一行程式碼。
函式pthread_join用來等待一個執行緒的結束。函式原型為:

  extern int pthread_join __P ((pthread_t __th, void **__thread_return));

  第一個引數為被等待的執行緒識別符號,第二個引數為一個使用者定義的指標,它可以用來

儲存被等待執行緒的返回值。這個函式是一個執行緒阻塞的函式,呼叫它的函式將一直等待到被等待的執行緒結束為止,當函式返回時,被等待執行緒的資源被收回。一個執行緒的結束有兩種途徑,一種是象我們上面的例子一樣,函式結束了,呼叫它的執行緒也就結束了;另一種方式是通過函式pthread_exit來實現。它的函式原型為:

  extern void pthread_exit __P ((void *__retval)) __attribute__ ((__noreturn__));

  唯一的引數是函式的返回程式碼,只要pthread_join中的第二個引數thread_return不是NULL,這個值將被傳遞給thread_return。最後要說明的是,一個執行緒不能被多個執行緒等待,否則第一個接收到訊號的執行緒成功返回,其餘呼叫pthread_join的執行緒則返回錯誤程式碼ESRCH。

2、修改執行緒的屬性
設定執行緒繫結狀態的函式為pthread_attr_setscope,它有兩個引數,第一個是指向屬性結構的指標,第二個是繫結型別,它有兩個取值:PTHREAD_SCOPE_SYSTEM(繫結的)和PTHREAD_SCOPE_PROCESS(非繫結的)。下面的程式碼即建立了一個繫結的執行緒。

#include
pthread_attr_t attr;
pthread_t tid;

/*初始化屬性值,均設為預設值*/
pthread_attr_init(&attr);
pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);

pthread_create(&tid, &attr, (void *) my_function, NULL);

3、執行緒的資料處理

和程序相比,執行緒的最大優點之一是資料的共享性,各個程序共享父程序處沿襲的資料段,可以方便的獲得、修改資料。但這也給多執行緒程式設計帶來了許多問題。我們必須當心有多個不同的程序訪問相同的變數。許多函式是不可重入的,即同時不能執行一個函式的多個拷貝(除非使用不同的資料段)。在函式中宣告的靜態變數常常帶來問題,函式的返回值也會有問題。因為如果返回的是函式內部靜態宣告的空間的地址,則在一個執行緒呼叫該函式得到地址後使用該地址指向的資料時,別的執行緒可能呼叫此函式並修改了這一段資料。在程序中共享的變數必須用關鍵字volatile來定義,這是為了防止編譯器在優化時(如gcc中使用-OX引數)改變它們的使用方式。為了保護變數,我們必須使用訊號量、互斥等方法來保證我們對變數的正確使用。

4、互斥鎖

互斥鎖用來保證一段時間內只有一個執行緒在執行一段程式碼。必要性顯而易見:假設各個執行緒向同一個檔案順序寫入資料,最後得到的結果一定是災難性的