多線程編程之Linux環境下的多線程(一)

來源:互聯網
上載者:User

標籤:分離   3.1   c中   函數調用   函數   bic   work   closed   共用   

一、Linux環境下的線程

  相對於其他動作系統,Linux系統核心只提供了輕量級進程的支援,並未實現執行緒模式。Linux是一種“多進程單線程”的作業系統,Linux本身只有進程的概念,而其所謂的“線程”本質上在核心裡仍然是進程。

     進程是資源分派的單位,同一進程中的多個線程共用該進程的資源(如作為共用記憶體的全域變數)。Linux中所謂的“線程”只是在被建立時clone了父進程的資源,因此clone出來的進程表現為“線程”,這一點一定要弄清楚。因此,Linux“線程”這個概念只有在打引號的情況下才是最準確的。

  目前Linux中最流行的線程機製為LinuxThreads,所採用的就是線程-進程“一對一”模型,調度交給核心,而在使用者級實現一個包括訊號處理在內的線程管理機制。LinuxThreads由Xavier Leroy負責開發完成,並已綁定在GLIBC中發行,它實現了一種BiCapitalized面向Linux的Posix 1003.1c “pthread”標準介面。Linuxthread可以支援Intel、Alpha、MIPS等平台上的多處理器系統。 

  需要注意的是,Linuxthread執行緒模式存在一些缺陷,尤其是在訊號處理、調度和進程間同步原語方面都存在問題。並且,這個執行緒模式也不符合POSIX標準的要求。為瞭解決LinuxThread的缺陷,RedHat開發了一套符合POSIX標準的新型執行緒模式:NPTL(Native POSIX Thread Library)。關於Linuxthread與NPTL的比較,請參考文章:Linux 執行緒模式的比較:LinuxThreads 和 NPTL。

二、Linux環境下的多線程編譯支援

  按照POSIX 1003.1c 標準編寫的程式與Linuxthread 庫相連結即可支援Linux平台上的多線程,在程式中需包含標頭檔pthread. h,在編譯連結時使用命令:

gcc -D -REENTRANT -lpthread xxx. c

  其中-REENTRANT宏使得相關庫函數(如stdio.h、errno.h中函數) 是可重新進入的、安全執行緒的(thread-safe),-lpthread則意味著連結庫目錄下的libpthread.a或libpthread.so檔案。  

  在一個多線程程式裡,預設情況下,只有一個errno變數供所有的線程共用。在一個線程準備擷取剛才的錯誤碼時,該變數很容易被另一個線程中的函數調用所改變。類似的問題還存在於fputs之類的函數中,這些函數通常用一個單獨的全域性地區來緩衝輸出資料。

       為解決這個問題,需要使用可重新進入的常式。可重新進入代碼可以被多次調用而仍然工作正常。編寫的多線程程式,通過定義宏_REENTRANT來告訴編譯器我們需要可重新進入功能,這個宏的定義必須出現於程式中的任何#include語句之前。

       _REENTRANT為我們做三件事情,並且做的非常優雅:

(1)它會對部分函數重新定義它們的可安全重入的版本,這些函數名字一般不會發生改變,只是會在函數名後面添加_r字串,如函數名gethostbyname變成gethostbyname_r。

(2)stdio.h中原來以宏的形式實現的一些函數將變成可安全重入函數。

(3)在error.h中定義的變數error現在將成為一個函數調用,它能夠以一種安全的多線程方式來擷取真正的errno的值。

三、Linux環境下的多線程函數

 3.1 線程建立

  在進程被建立時,系統會為其建立一個主線程,而要在進程中建立新的線程,則可以調用pthread_create函數:

#include <pthread.h>int pthread_create(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);

  參數說明:

  • thread:指向pthread_create類型的指標,用於引用新建立的線程。
  • attr:用於設定線程的屬性,一般不需要特殊的屬性,所以可以簡單地設定為NULL。
  • start_routine:傳遞新線程所要執行的函數地址。
  • arg:新線程所要執行的函數的參數。

  傳回值:

  調用如果成功,則傳回值是0;如果失敗則返回錯誤碼。

  每個線程都有自己的線程ID,以便在進程內區分。線程ID在pthread_create調用時回返給建立線程的調用者;一個線程也可以在建立後使用pthread_self()調用擷取自己的線程ID: 

pthread_self (void);

3.2 線程退出

  線程的退出方式有三種:

(1)執行完成後隱式退出;

(2)由線程本身顯示調用pthread_exit 函數退出;

pthread_exit (void * retval);

 

(3)被其他線程用pthread_cance函數終止:

pthread_cancel (pthread_t thread);

 

  如果一個線程要等待另一個線程的終止,可以使用pthread_join函數,該函數的作用是調用pthread_join的線程將被掛起直到線程ID為參數thread的線程終止:

pthread_join (pthread_t thread, void** threadreturn);

 

3.3 簡單的多線程樣本

  一個簡單的Linux多線程樣本如下:

 View Code

  編譯語句如下:

gcc -D_REENTRANT thread1.c -o thread1 –lpthread

  輸出結果是:

$./thread1[輸出]:thread_function is running. Argument was Hello WorldWaiting for thread to finish...Thread joined, it returned Thank you for your CPU time!Message is now Bye!

 

  在這個例子中,pthread_exit(void *retval)本身返回的就是指向某個對象的指標,因此,pthread_join(pthread_t th, void **thread_return);中的thread_return是二級指標,指向線程傳回值的指標。可以看到,我們建立的新線程修改的數組message的值,而原先的線程也可以訪問該數組。如果我們調用的是fork而不是pthread_create,就不會有這樣的效果了。因為fork建立子進程之後,子進程會拷貝父進程,兩者分離,相互不干擾,而線程之間則是共用進程的相關資源。

 

小結:

  本文主要講了Linux環境下的多線程基本概念,包括多線程的實現方式、函數介面、功能特性等。

 

多線程編程之Linux環境下的多線程(一)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.