1. 程式人生 > >Linux下執行緒的概念和使用

Linux下執行緒的概念和使用

一. 概念
  首先Linux並不存在真正的執行緒,Linux的執行緒是使用程序模擬的。當我們需要在一個程序中同時執行多個執行流時,我們並不可以開闢多個程序執行我們的操作(32位機器裡每個程序認為它 獨享 4G的記憶體資源),此時便引入了執行緒,例如當我們既需要下載內容,又需要瀏覽網頁時,此時多執行緒便起了作用。執行緒是承擔排程的基本單位,一個程序可擁有多個執行緒,它的執行力度比程序更加細緻,執行緒資源共享。
二. 特點
  由於同一程序的多個執行緒共享同一地址空間,所以程式碼段,資料段是共享的,如果定義一個函式(儲存在程式碼段),各執行緒都可以進行呼叫,如果定義個全域性變數(儲存在資料段),在各執行緒中都可以訪問到,除此之外,各執行緒還共享以下程序資源和環境:
1.檔案描述符表
2.每種訊號的處理方式(SIG_IGN,SIG_DFL,使用者自定義)
3.當前工作目錄
4.使用者id和組id
但有些資源是執行緒獨享

的:
1.執行緒id
2.上下文,包括各種暫存器的值,程式計數器和棧指標
3.棧空間
4.errno變數
5.訊號遮蔽字
6.排程優先順序
三. 執行緒的簡單實用
1.建立執行緒

int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);

  返回值:成功返回0,失敗返回錯誤號。在一個執行緒中調pthread_create()建立新的執行緒後,當前執行緒從pthread_create()返回繼續往下執行,新的執行緒所執行的程式碼由我們傳給pthread_create的函式指標start_routine決定。
  thread引數傳入執行緒的id,void

( star_routine)(void )由使用者進行撰寫。
2.執行緒終止
  void pthread_exit(void *retval)函式用於程序終止,傳入一個id,呼叫exit()的話,主程序會終止。終止執行緒由三種方法:
1).從執行緒函式return。這種方法法對主執行緒不適用,從main函式return相當於呼叫exit。
2).一個執行緒可以呼叫pthread_cancel終止同一程序中的另一個執行緒。
3).執行緒可以調pthread_exit終自己。
  retval是void *型別,其它執行緒可以調pthread_join獲得這個指標。
3.執行緒等待

  int pthread_join(pthread_t thread,void **retval);成功返回0,失敗返回錯誤號。 執行緒的等待是以阻塞式等待,執行緒不等待會產生記憶體洩露(類似程序的殭屍程序)
4.程序取消
  在合理範圍內,執行緒可以自我或者被別人取消。取消後返回PTHREAD_CANCELED(它被定義為(void *)-1),取消呼叫函式pthread_cancel(id);
5.執行緒分離
  在任何一個時間點上執行緒是可結合的(joinable)或者是分離的(detached)。一個可結合的執行緒能夠被其他執行緒收回其資源和殺死。在被其他執行緒回收之前,它的儲存器資源(例如棧)是不釋放的。相反一個分離的執行緒是不能被其他執行緒回收或殺死的,它的儲存器資源在它終時時由系統自動釋放。
  預設情況一個執行緒是可結合的,每一個可結合的執行緒都應該被顯性的回收,既呼叫pthread_join()函式,分離呼叫函式pthread_detach。分離的這個函式是非阻塞的,可以立即返回。但為什麼要分離呢?因為主程序在處理執行緒時,要處理不止一個,而每一個都需要被等待,然而join是阻塞式的,這樣的話就只能處理一個執行緒,所以要加入分離,這樣就可以處理多個執行緒。呼叫pthread_detach()後,這些子程序的狀態會被設定為分離的,該執行緒執行結束會自動釋放所有資源。
  下面為測試程式碼:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

void* thread1()
{
    pthread_detach(pthread_self());//分離後仍可被等待
    printf("pid is: %d, tid is: %d\n", getpid(),pthread_self());
    return (void*)1;
}
int main()
{
    pthread_t tid;
    void *ret;
    int err = pthread_create(&tid, NULL, thread1, NULL);
    if (err != 0)
    {
        perror("pthread_create\n");
        return err;
    }
    //如果直接執行等待程式碼,一般會等待成功,返回1
    //如果在等待之前加入取消。等待錯誤,返回-1
    //  pthread_cancel(tid);
    //執行緒可以自我取消也可以被取消,執行緒終止
    //呼叫pthread_exit(tid);和取消同樣用法。
    int tmp = pthread_join(tid, &ret);
    if (tmp == 0)
    {
        printf("wait success\n");
    }
    else
    {
        printf("wait failed\n");
    }
    printf(" pid is: %d, tid is: %d\n", getpid(),pthread_self());
    sleep(1);
    return 0;
}