Linux 多線程通信


 摘自資料(linux 與Windows不同)

     線程間無需特別的手段進行通信,由於線程間能夠共享數據結構,也就是一個全局變量能夠被兩個線程同一時候使用。只是要注意的是線程間須要做好同步,一般用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、線程的數據處理

和進程相比,線程的最大長處之中的一個是數據的共享性,各個進程共享父進程處沿襲的數據段,能夠方便的獲得、改動數據。但這也給多線程編程帶來了很多問題。我們必須當心有多個不同的進程訪問同樣的變量。很多函數是不可重入的,即同一時候不能執行一個函數的多個拷貝(除非使用不同的數據段)。在函數中聲明的靜態變量經常帶來問題,函數的返回值也會有問題。由於假設返回的是函數內部靜態聲明的空間的地址,則在一個線程調用該函數得到地址后使用該地址指向的數據時,別的線程可能調用此函數並改動了這一段數據。在進程中共享的變量必須用keywordvolatile來定義,這是為了防止編譯器在優化時(如gcc中使用-OX參數)改變它們的使用方式。為了保護變量,我們必須使用信號量、相互排斥等方法來保證我們對變量的正確使用。

4、相互排斥鎖

相互排斥鎖用來保證一段時間內僅僅有一個線程在運行一段代碼。必要性顯而易見:如果各個線程向同一個文件順序寫入數據,最后得到的結果一定是災難性的



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM