Linux多線程編程——線程的建立與退出

POSIX線程標準:該標準定義了建立和操縱線程的一整套API。在類Unix操做系統(Unix、Linux、Mac OS X等)中,都使用Pthreads做爲操做系統的線程。Windows操做系統也有其移植版pthreads-win32。雖然說如今c++11也把線程加入了標準庫,但須要gcc4.8版本以上的編譯器才能很好的支持,因此這裏咱們仍然學習posix線程標準,並且二者相差不大,學習多線程,主要是學習如何解決併發問題,如何解決多線程程序之間的同步和互斥問題。c++

線程概念:編程

線程,有時被稱爲輕量級進程(Lightweight Process,LWP),是程序執行流的最小單元。一個標準的線程由線程ID,當前指令指針(PC),寄存器集合和堆棧組成。另外,線程是進程中的一個實體,是被系統獨立調度和分派的基本單位,線程本身不擁有系統資源,只擁有一點兒在運行中必不可少的資源,但它可與同屬一個進程的其它線程共享進程所擁有的所有資源。一個線程能夠建立和撤消另外一個線程,同一進程中的多個線程之間能夠併發執行。因爲線程之間的相互制約,導致線程在運行中呈現出間斷性。線程也有就緒、阻塞和運行三種基本狀態。就緒狀態是指線程具有運行的全部條件,邏輯上能夠運行,在等待處理機;運行狀態是指線程佔有處理機正在運行;阻塞狀態是指線程在等待一個事件(如某個信號量),邏輯上不可執行。每個程序都至少有一個線程,若程序只有一個線程,那就是程序自己。
線程是程序中一個單一的順序控制流程。進程內一個相對獨立的、可調度的執行單元,是系統獨立調度和分派CPU的基本單位指運行中的程序的調度單位。在單個程序中同時運行多個線程完成不一樣的工做,稱爲多線程。——百度百科
學習編程最好是動手寫代碼,下面我會列出一些關於線程操做的api,並經過例子演示關於多線程程序如何寫以及如何解決多線程程序之間的同步和互斥問題。
線程ID數據類型:pthread_t 線程屬性類型:pthread_attr_t 
#include <pthread.h>
int              pthread_equal(pthread_t tid1,pthread_t tid2); //判斷2個線程ID是否相同,如果返回非0數值,不然返回0
pthread_t  pthread_self(void)                                                //得到線程ID
 
線程建立
int pthread_create(pthread_t *restrict tidp,                           
         const pthread_attr_t * restrict attr,            
         void *(*start_rtn)(void *),                           
         void *restrict arg);    
                                  
建立線程,restrict關鍵字,代表指針所指向的內容,不能經過除此指針以外的其餘直接或間接的方式修改,attr參數用來設置線程屬性,通常設爲NULL,建立一個具備默認屬性的線程,start_rtn線程調用的函數,arg表示線程調用的函數的參數,在這個函數返回以前新線程可能已經開始運行了,建立一個線程後,也可能主線程已經結束了,新線程還沒開始執行,整個進程就可能已經終止了成功返回0.
 
線程終止
void pthread_exit(void *rval_ptr);  
//終止線程,rval_ptr用來設置線程退出時的返回值,與return做用相似但有不一樣return不會調用清理程序,而exit會。
 
int pthred_join(pthread_t thread,void **rval_ptr);
//等待線程終止並得到線程的退出狀態,rval_ptr用來得到線程退出值,若設爲NULL,則只等待線程退出。注意指針指向的內存的生命週期,成功返回0
 
int pthread_cancel(pthread_t tid);                
//使用該函數代表但願線程退出,這時,被取消的線程會在某個時間,調用線程清理處理程序,就像進程退出時會調用某些函數完成清理工做
 
void pthread_cleanup_push(void (*rtn)(void *),void *arg);
 //爲線程註冊清理程序,在線程退出時調用,先註冊的後調用,與atexit函數相似
 
void pthread_cleanup_pop(int execute);  
//取消上一個註冊的清理程序通常設爲0
 
在默認狀況下,線程的終止狀態會保存直到對該線程調用pthread_join,若是線程已經被分離,線程的底層存儲資源能夠在線程終止時當即被收回。在線程分離後不能調用pthread_join,能夠調用pthread_detach分離線程
int pthread_detach(pthread_t tid);
代碼演示
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
void cleanup(void *arg)
{
    printf("cleanup: %s\n",(char *)arg);
}

void *thr_fn1(void *arg)
{
    printf("thread 1 start \n");
    pthread_cleanup_push(cleanup,"thread 1 first handler");
    pthread_cleanup_push(cleanup,"thread 1 second handler");
    printf("thread 1 push complete\n");
    if(arg)
        return ((void *)1);              //這裏是return,註冊的清理函數不會執行
    
    pthread_cleanup_pop(0);
    pthread_cleanup_pop(0);
    return ((void *)1);
}

void *thr_fn2(void *arg)
{
    printf("thread 2 start \n");
    pthread_cleanup_push(cleanup,"thread 2 first handler");
    pthread_cleanup_push(cleanup,"thread 2 second handler");
    printf("thread 2 push complete\n");
    if(arg)
        pthread_exit((void *)2);     //這裏是pthread_exit,清理函數會執行
    
    pthread_cleanup_pop(0);
    pthread_cleanup_pop(0);
    pthread_exit((void *)2);
}

int main()
{
    int err;
    pthread_t tid1,tid2;
    void *tret;
    err=pthread_create(&tid1,NULL,thr_fn1,(void *)1);
    if(err!=0)
    {
        perror("pthread_create");
        exit(-1);
    }

    err=pthread_create(&tid2,NULL,thr_fn2,(void *)1);
    if(err!=0)
    {
        perror("pthread_create");
        exit(-1);
    }

    err=pthread_join(tid1,&tret);
    if(err!=0)
    {
        perror("pthread_join");
        exit(-1);
    }
    printf("thread1 exit code is %ld\n",(long)tret);

    err=pthread_join(tid2,&tret);
    if(err!=0)
    {
        perror("pthread_join");
        exit(-1);
    }
    printf("thread2 exit coid is %ld\n",(long)tret);
    exit(0);
}

 線程屬性api

相關文章
相關標籤/搜索