線程的建立和控制

線程的定義:
線程,有時被稱爲輕量級進程(Lightweight Process,LWP),是程序執行流的最小單元。一個標準的線程由線程ID,當前指令指針(PC),寄存器集合和堆棧組成。另外,線程是進程中的一個實體,是被系統獨立調度和分派的基本單位,線程本身不擁有系統資源,只擁有一點兒在運行中必不可少的資源,但它可與同屬一個進程的其它線程共享進程所擁有的所有資源。一個線程能夠建立和撤消另外一個線程,同一進程中的多個線程之間能夠併發執行。因爲線程之間的相互制約,導致線程在運行中呈現出間斷性。線程也有就緒、阻塞和運行三種基本狀態。就緒狀態是指線程具有運行的全部條件,邏輯上能夠運行,在等待處理機;運行狀態是指線程佔有處理機正在運行;阻塞狀態是指線程在等待一個事件(如某個信號量),邏輯上不可執行。每個程序都至少有一個線程,若程序只有一個線程,那就是程序自己。
線程是程序中一個單一的順序控制流程。進程內一個相對獨立的、可調度的執行單元,是系統獨立調度和分派CPU的基本單位指運行中的程序的調度單位。在單個程序中同時運行多個線程完成不一樣的工做,稱爲多線程。
各線程還共享如下進程資源和環境:
1. 文件描述符表
2. 每種信號的處理方式(SIG_IGN、 SIG_DFL或者自定義的信號處理函數)
3. 當前工做目錄
4. 用戶id和組id
但有些資源是每一個線程各有一份的:
1. 線程id
2. 上下文,包括各類寄存器的值、程序計數器和棧指針
3. 棧空間
4. errno變量
5. 信號屏蔽字
6. 調度優先級
咱們將要學習的線程庫函數是由POSIX標準定義的,稱爲POSIX thread或者pthread。在Linux上線 程函數位於libpthread共享庫中,所以在編譯時要加上-lpthread選項

線程建立:
相關函數:多線程

wKiom1cZ9eXAdDyLAAA2W1wy1Go857.png

返回值:成功返回0,失敗返回錯誤號。在一個線程中調用pthread_create()建立新的線程後,當前線程從pthread_create()返回繼續往下執行,而新的線程所執行的代碼由咱們傳給pthread_create的函數指針start_routine決 定。start_routine函數接收一個參數,是經過pthread_create的arg參數傳遞給它的,該
參數的類型爲void *,這個指針按什麼類型解釋由調用者本身定義。
start_routine的返回值類型也是void *,這個指針的含義一樣由調用者本身定義。 start_routine返回時,這個線程就退出了,其它線程 能夠調用pthread_join獲得start_routine的返回值,相似於父進程調用wait(2)獲得子進程的退出 狀態。併發

代碼實現:ide

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

pthread_t tid;
void* thread_run(void* _val)
{
 printf("%s:pid is :%d,tid is:%u\n", (char*)_val,(int)getpid(),(unsigned long long)pthread_self());
 return NULL;
}

int main()
{
    int err=pthread_create(&tid,NULL,thread_run,"other thread run");
    if(err!=0)
    {
        printf("create thread error!info is:%s\n",strerror(err));
        exit(err);
    }
  printf("main thread run:pid is:%d,tid is:%u\n",(int)getpid(),(unsigned long long)pthread_self());
  sleep(1);
    return 0;
}

運行結果:函數

wKioL1cZ-hHwnJIMAAAq1PVnYxI533.png

分析:一、在Linux上,thread_t類型是一個地址值,屬於同一進程的多個線程調用getpid(2)能夠獲得相同的進程號,而調用pthread_self(3)獲得的線程號各不相同。
二、因爲pthread_create的錯誤碼不保存在errno中,所以不能直接用perror(3)打印錯誤信息,能夠先用strerror(3)把錯誤碼轉換成錯誤信息再打印。
三、若是任意一個線程調用了exit或_exit,則整個進程的全部線程都終止,因爲從main函數return也至關於調用exit,爲了防止新建立的線程尚未獲得執行就終止,咱們在main函數return以前延 時1秒,這只是一種權宜之計,即便主線程等待1秒,內核也不必定會調度新建立的線程執行

線程終止:

1. 從線程函數return。這種方法對主線程不適用,從main函數return至關於調用exit。
2. 一個線程能夠調用pthread_cancel終止同一進程中的另外一個線程。
3. 線程能夠調用pthread_exit終止本身。學習

線程等待:
1. 若是thread線程經過return返回,value_ptr所指向的單元裏存放的是thread線程函數的返回值。
2. 若是thread線程被別的線程調用pthread_cancel異常終掉,value_ptr所指向的單元裏存放的是常數PTHREAD_CANCELED。
3. 若是thread線程是本身調用pthread_exit終止的,value_ptr所指向的單元存放的是傳給pthread_exit的參數。 若是對thread線程的終止狀態不感興趣,能夠傳NULL給value_ptr參數spa

相關函數:線程

wKioL1cZ97DiZ8TqAAAqmFV9rgk161.png

wKiom1cZ9w6jCkUNAAAp7H6GplQ745.png

wKiom1cZ976TUDNcAAAp_JT4NOQ096.png


代碼實現:指針

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

void *thread1(void *_val)
{
    printf("thread1 returning...\n");
    return (void*)1;
}


void *thread2(void *_val)
{
    printf("thread2 returning...\n");
    pthread_exit( (void*)2);
}

void *thread3(void *_val)
{
    while(1)
    {
        printf("pthread 3 is running,wait for be cancel...\n");
        sleep(1);
    }
    return NULL;
}

int main()
{
    pthread_t tid;
    void *tret;
    pthread_create(&tid,NULL,thread1,NULL);
    pthread_join(tid,&tret);
    printf("thread return,thread id is:%u,return code is:%d\n",(unsigned long)tid,(int)tret);

    pthread_create(&tid,NULL,thread2,NULL);
    pthread_join(tid,&tret);
    printf("thread exit,thread id is:%u,exit code is:%d\n",(unsigned long)tid,(int)tret);

    pthread_create(&tid,NULL,thread3,NULL);
    sleep(3);
    pthread_cancel(tid);
    pthread_join(tid,&tret);
    printf("thread return,thread id is:%u,cancel code is:%d\n",(unsigned long)tid,(int)tret);
    return 0;
}

運行結果:code

wKioL1cZ-WCSkxNBAAAzKHvDXps090.png


線程分離:
線程是可結合的( joinable)或者是分離的( detached) 。 一個可結合的線程可以被其餘線程收回其資源和殺死。在被其餘線程回收以前,它的存儲器資源(例如棧)是不釋放的。 相反, 一個分離的線程是不能被其餘線程回收或殺死的,它的存儲器 資源在它終止時由系統自動釋放。

線程默認狀況下被建立成可結合的,爲了不存儲器泄漏,每一個可結合線程都應該要麼被顯示地回收(調用pthread_join),要麼經過調用pthread_detach被分離。調用pthread_join後,若是線程沒有運行結束,調用者會被阻塞。blog

相關函數:

wKiom1cZ-NKgaFJDAAAooXvoEi8330.png


代碼:

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

void *thread_run(void *_val)
{
    pthread_detach(pthread_self());
    printf("%s\n",(char*)_val);
    return NULL;
}

int main()
{
    pthread_t tid;
    int tret=pthread_create(&tid,NULL,thread_run,"thread1 run...");
    if(tret!=0)
    {
        printf("create thread error!,info is:%s\n",strerror(tret));
        return tret;
    }

    int ret=0;
    sleep(1);
    if(0==pthread_join(tid,NULL))
    {
        printf("pthread wait success!\n");
        ret=0;
    }
    else
    {
        printf("pthread wait failed!\n");
        ret=1;
    }
    return ret;
}

運行結果:

wKiom1cZ-SvSIrl3AAAjT5c7I00803.png

相關文章
相關標籤/搜索