linux多線程pthread

1.Linux線程的發展

   早在LINUX2.2內核中。並不存在真正意義上的線程,當時Linux中常用的線程pthread實際上是通過進程來模擬的,也就是同過fork來創建“輕”進程,並且這種輕進程的線程也有個數的限制:最多只能有4096和此類線程同時運行。
   2.4內核消除了個數上的限制,並且允許在系統運行中動態的調整進程數的上限,當時採用的是Linux Thread 線程庫,它對應的線程模型是“一對一”,而線程的管理是在內核爲的函數庫中實現,這種線程得到了廣泛的應用。但是它不與POSIX兼容。另外還有許多諸如信號處理,進程ID等方面的問題沒有完全解決。
   相似新的2.6內核中,進程調度通過重新的編寫,刪除了以前版本中的效率不高的算法,內核框架頁也被重新編寫。開始使用NPTL(Native POSIX Thread Library)線程庫,這個線程庫有以下幾個目標: POSIX兼容,都處理結果和應用,底啓動開銷,低鏈接開銷,與Linux Thread應用的二進制兼容,軟硬件的可擴展能力,與C++集成等。 這一切是2.6的內核多線程機制更加完備。

 

2.Linux 線程的實現

Linux線程的基本操作
這裏主要講的線程以及相關操作都是用戶空間的線程操作,在Linux中,一般pthread線程庫是一套通用的線程庫,是由POSIX提出的,因此具有很好的可移植性。
  2.1 線程的創建: 創建線程通常使用的函數是pthread_create.

  2.2 線程的退出:

      1) 在線程創建以後,就開始運行相關的線程函數,在該函數運行完之後,該線程也就退出了。這是線程退出的一種方法: 運行完畢,自動退出;

      2) 調用pthread_exit函數主動退出;

      3) 進程終止函數exit函數,一旦結束了進程,那麼此進程中所有線程都將無條件終止。
一個注意點:在默認線程屬性下,如果一個進程有很多線程在同時運行,一個線程在退出以後,當前線程所佔用的資源並不會隨着線程的終止而得到釋放。因爲所有處在一個進程中的線程共享資源。
線程中還有一個常用函數:pthread_join函數可以用於將當前線程掛起,等待其他線程結束。實際上,這個函數是就是一個線程阻塞函數,調用它的函數將一直等待到被等待的線程結束爲止。當函數返回時,被等待線程的資源就被回收。
pthread_create 函數:

所需文件頭:

#include <pthread.h>

函數原型:

int pthread_create((pthread_t*thread,pthread_attr_r*attr,void*(*start_routine)
(void*),void *arg))

函數傳入值:

thread:線程標識符

 

attr: 線程屬性設置 null表示採用默認

 

start_roitine : 線程函數的啓示地址

 

arg :傳遞給start_routine的參數

函數返回值:

成功:0
出錯:-1

pthread_exit函數

所需文件頭:

#include <pthread.h>

函數原型:

Void pthread_exit(void *retval)

函數傳入值:

retval:調用者線程的返回值,可由其他函數如pthread_join來檢索獲取。

pthread_join函數

所需文件頭:

#include <pthread.h>

函數原型:

int pthread_join ((pthread_t th,void **thread_return))

函數傳入值:

th: 等待線程的標識符
thread_return:用戶定義的指針,用來存儲被等待線程的返回值(不爲NULL時)

函數返回值:

成功:0

 

出錯:-1

取消一個線程
有時候,我們想讓一個線程 能夠請求另外一個線程結束,就像給它發送一個信號似的。用線程程是可以完成這一操作的,而與單處理經,線程在被要求結束執行的時候還有一種改變其行爲的辦法。
我們來看看要求一個線程結束執行的函數

所需文件頭:

#include <pthread.h>

函數原型:

int pthread_cancel(pthread_t thread);

函數傳入值:

thread:線程的標識符

函數返回值:

成功:0

 

出錯:-1

這個定義很明白,給定一個線程標識符,我們就能要求取消它。但在取消線形程請求的接收端,事情會稍微複雜一些,好在也不是太複雜。線形程可以用pthread_setcancelstate設置自己的取消狀態,下面是這個函數的定義:

所需文件頭:

#include <pthrea.h>

函數原型:

int pthread_setcancelstate(int state,int *oldstate);

函數傳入值:

state:可以是PTHREAD_CANCEL_ENABLE,這個值允許線程接收取消請求;還可以是PTHREAD_CANCEL_DISABLE,它的作用是屏幕它們。
線程以前的取消狀態可以用oldstate指針檢索出來。如果沒興趣可以傳一個NULL進去。

函數返回值:

成功:0

 

出錯:-1

如果取消請求被接受了,線程會進入第二個控制層次----用pthread_setcanceltype設置取消類型。

所需文件頭:

#include <pthrea.h>

函數原型:

int pthread_setcanceltype(int type,int *oldstate);

函數傳入值:

type:可以有兩種取值,一個是PTHREAD_CANCEL_ASYNCHORONOUS,接收到取消請求之後立刻採取行動;另一個是PTHREAD_CANCEL_DEFERRED,在接收到取消請求之後、採取實際行動之前,先執行以下幾個函數之一:pthread_join、pthread_cond_wait、pthread_cond_timewait、pthread_testcancel、sem_wait或sigwait。

函數返回值:

成功:0

 

出錯:-1

稍微注意一點就是在android-ndk-r3 裏是不支持int pthread_cancel(pthread_t thread); 所以想強制退出線程似乎沒有更好的辦法。

=================================================================================

 

linux多線程pthread的函數聲明在<pthread.h>中,因此在使用該函數時,需要把該頭文件引入。

 
線程的創建

1、創建

int pthread_create( pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(* func) (void *), void *restrict arg );

attr: 線程屬性包括:優先級、初始棧大小,是否應該成爲一個守護線程。

缺省設置,NULL

tidp是要創建的線程,創建成功後tipd爲先線程的id

 

void *(* func) (void *)是一個函數指針,該函數指針的類型爲void* (*)(void *)

是一個參數爲void *,返回值也爲void *的函數類型。它的一個簡單的例子如下

void *thread_handler(void *arg)

{

 return NULL;

}

void *restrict arg

中的arg是void *(* func) (void *)函數指針的參數。

補充:函數聲明中多次出現了restrict,其實這是用於CPU對函數的優化使用的,restrict的使用,由程序員保證使用restrict標誌的參數間不會有內存重疊。

 

獲取線程自身的id

pthread_t pthread_self(void);

 

等待給定線程終止

int pthread_join( pthread_t tid, void **status);

statues返回等待線程的返回值

單個線程有三種退出方式

1.線程從啓動例程中返回(return方式),返回值是現成的退出碼

2.線程被同一進程內的其他線程取消

3.線程調用pthread_exit退出。void pthread_exit(void *rval_ptr)

 

線程清理處理程序

void pthread_clean_push(void (*rtn)(void *),void *arg)

void pthread_clean_pop(iny excute)

清理函數rtn的調用順序是由pthread_clean_push函數安排的。

它在下列幾種情況下執行:

1.調用pthread_exit時

2.響應取消請求時

3.用非零execute參數調用pthread_clean_pop時

如果execute參數爲0,清理函數將不被調用。無論何種情況,pthread_clean_pop都將刪除上次pthread_clean_push建立的清理處理程序。

如果線程使用return從例程返回,那麼pthread_clean_push建立的清理處理程序不會被執行。

 

linux thread與fork的對比

 進程原語 線程原語  描述 
 fork pthread_create   創建新的控制流
 exit pthread_exit  從現有的控制流退出
 waitpid pthread_join  從控制流中得到退出狀態
 atexit pthread_clean_push  註冊在退出控制流時執行的函數
 getpid pthread_self  獲得控制流ID
 abort pthread_cancel  請求控制流的非正常退出

 

=================================================================================

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章