線程概述

 

clone函數調用
    #include <sched.h>
    int clone(int (*fn)(void *fnarg), void *child_stack, int flags, void *arg, ...
                 /* pid_t *pid, struct user_desc *tls, pid_t *ctid */ );
    int __clone2(int (*fn)(void *),  void *child_stack_base,size_t stack_size, int flags, void *arg, ...
                 /* pid_t *pid, struct user_desc *tls, pid_t *ctid */ );
    指向子進程執行時調用的函數,fnarg是傳給該函數的參數,child_stack是你爲子進程分配的堆棧指針,flags通過將下表中的值相或得到,arg被傳送給子函數,他的取值和用法完全有你決定,因爲他爲函數提供了上下文,用他從父進程向任何子進程傳送數據,clone返回創建進程的進程ID,出錯的話返回-1,設置errno,並不建立子進程。
    CLONE_VM                若設置,父子進程運行在同一段內存
    CLONE_FS                若設置,父子進程共享在root文件系統,當前工作目錄以及umask信息
    CLONE_FILES         若設置,父子信息共享文件描述服
    CLONE_SIGHAND       若設置,父子進程共享在父進程上的信號處理器
    CLONE_PID           若設置,父子進程具有相同的PID

pthread接口
    一,建立一個新的線程
        #include <pthread.h>
        int pthread_create(pthread_t *restrict thread,
              const pthread_attr_t *restrict attr,
              void *(*start_routine)(void*), void *restrict arg);
        thread用來保存新線程的標識符,attr決定了對線程應用哪種線程屬性,start_routine指向線程要執行的函數的指針,arg他是傳遞給前面的函數的參數,如果他有意義,則由用戶來定義。pthread_create()執行成功返回0,並在thread中保存線程的標識符,失敗則返回一個非零的退出碼。
    二,結束一個線程
        #include <pthread.h>
        void pthread_exit(void *value_ptr);
        pthread_exit()函數用來終止當前的線程,並返回valure_ptr,該值可由父線程或其他線程通過pthread_join來檢索。一個線程也可以簡單的從其初始化函數的返回來終止。
    三,等待一個線程結束
        #include <pthread.h>
        int pthread_join(pthread_t thread, void **value_ptr);
        函數pthread_join()用來掛起當前的線程,直到thread指定的線程運行結束爲止。thread用來指定線程,value_ptr爲用戶定義的一個指針,他可以用來存儲等待進程的返回值。其他線程不能對同一線程再應用pthread_join函數。
    四,登記函數
        #include <pthread.h>
        int pthread_atfork( void (*prepare)(void),  /*在創建新線程之前調用*/
                                    void (*parent)(void),   /*在父線程中隨後調用*/
                                    void (*child)(void));   /*建立好子線程後立即在子線程中調用*/
        pthread_atfork()函數登記三個函數,用來在某個時間來調用。他們都可以爲NULL,此時,對應的函數將不發生調用。可以通過多次調用pthread_atfork函數登記多組處理函數。如果執行成功返回0,否則返回出錯代碼。注意,在即將出臺的POSIX線程標準中,將不再包含pthread_atfork的調用。
    五,取消線程
        #include <pthread.h>
        int pthread_cancel(pthread_t thread);
        int pthread_setcancelstate(int state, int *oldstate);
        int pthread_setcanceltype(int type, int *oldtype);
        void pthread_testcancel(void);
        pthread_cancel用來取消thread指定的線程,pthread_setcancelstate用來設置他的取消狀態,state是新狀態,oldstate用來保存舊的狀態,他可以是NULL,state的值可以是:
            PTHREAD_CANCEL_ENABLE   允許請求取消
            PTHREAD_CANCEL_DISABLE  忽略取消請求
        pthread_setcanceltype用來改變一個線程對取消請求的響應方式,type的取值可以是:
            PTHREAD_CANCEL_ASYNCHRONOUS 立即取消
            PTHREAD_CANCEL_DEFERRED         延遲取消直至下一個取消點,取消點用pthread_setcancel來建立,如果有任何正被掛起的取消請求,這個函數就會取消當前的線程,還類函數中,如果成功返回0,否則返回出錯代碼。
    六,線程結束處理
        #include <pthread.h>
        void pthread_cleanup_pop(int execute);
        void pthread_cleanup_push(void (*routine)(void*), void *arg);
        當在線程中調用pthread_exit或者線程允許取消請求,而又到達一個取消點時,就調用routine函數,並將arg作爲參數。處理函數被壓入一個棧中,所以,當使用pthread_cleanup_pop時,取消最近的一個壓入的函數,如果execute不爲0,表明棧中還有可用的處理函數,此時,也會被執行,POSIX標準要求,每一個入棧操作都要對應一個出棧操作。
    七,線程掛起
        #include <pthread.h>
        pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
        int pthread_cond_destroy(pthread_cond_t *cond);
        int pthread_cond_init(pthread_cond_t *restrict cond,
              const pthread_condattr_t *restrict attr);
        int pthread_cond_broadcast(pthread_cond_t *cond);
        int pthread_cond_signal(pthread_cond_t *cond);
        int pthread_cond_timedwait(pthread_cond_t *restrict cond,
              pthread_mutex_t *restrict mutex,
              const struct timespec *restrict abstime);
        int pthread_cond_wait(pthread_cond_t *restrict cond,
              pthread_mutex_t *restrict mutex);
        函數pthread_cond_init()用來初始化一個cond_t類型的對象,Linux中會忽略第二個參數,大多數的Linux的pthread程序只是簡單的把PTHREAD_COND_INITIALIZER複製給attr,函數pthread_cond_destory()是cond_t類型對象的析構器,檢查有沒有線程正在等待條件的情況。pthread_cond_signal用來重啓一個並且唯一的一個正在等待條件的進程 ,pthread_cond_broatcase與pthread_cond_signal的區別是他會重啓所有正在等待條件的線程。這兩個函數中的cond參數表示條件。pthread_cond_wait用來解開mutex指出的一個互斥鎖,然後等待變量cond上的信號,pthread_cond_timedwait函數的功能與此類似,但他只等待abstime指定的時間。上述所有的函數成功後返回0,而在出錯時返回錯誤代碼。
    八,線程比較
        #include <pthread.h>
        int pthread_equal(pthread_t t1, pthread_t t2);
        這個函數用來比較線程ID t1,t2引用的是不是同一個線程,是則返回0,否則返回非0;
    九,線程屬性
        線程的屬性控制着一個線程在他整個生命週期的行爲,
        屬性                值                                  含義
        datachstatc     PTHREAD_CREATE_JOINABLE     可切入的狀態
                            PTHREAD_CREATE_DETACHED     被分離的狀態
        schedpolicy     SCHED_OTHER                     正常,非實時
                            SCHED_RR                            實時,循環
                            SCHED_FIFO                      實時,先入先出
        schedparam      與策略有關
        inheritsched    PTHREAD_EXPLICIT_SCHED      由schedpolice和schedparam設置,從
                            PTHREAD_INHERIT_SCHED       父進程繼承
        scope               PTHREAD_SCOPE_SYSTEM            一個線程一個系統時間片,線程共享系統
                            PTHREAD_SCOPE_PROCESS       時間片(Linux不支持)
        下列函數控制者線程屬性對象,注意,這些調用不能控制和線程直接相關聯的屬性,產生的屬性對象通常要傳遞給pthread_create函數。
        #include <pthread.h>
        int pthread_attr_destroy(pthread_attr_t *attr);
        int pthread_attr_init(pthread_attr_t *attr);
        int pthread_attr_getdetachstate(const pthread_attr_t *attr,
              int *detachstate);
        int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
        int pthread_attr_getschedpolicy(const pthread_attr_t *restrict attr,
              int *restrict policy);
        int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy);
        int pthread_attr_getschedparam(const pthread_attr_t *restrict attr,
              struct sched_param *restrict param);
        int pthread_attr_setschedparam(pthread_attr_t *restrict attr,
              const struct sched_param *restrict param);
        int pthread_attr_getinheritsched(const pthread_attr_t *restrict attr,
              int *restrict inheritsched);
        int pthread_attr_setinheritsched(pthread_attr_t *attr,
              int inheritsched);
        int pthread_attr_getscope(const pthread_attr_t *restrict attr,
              int *restrict contentionscope);
        int pthread_attr_setscope(pthread_attr_t *attr, int contentionscope);
    十,互斥
        用來保護被多個線程共享的數據不會被同時修改。一個互斥鎖只有兩種狀態,加鎖與解鎖,加鎖的互斥不但不讓其他線程訪問,而且互斥也規上鎖進程所有,任何進程都能訪問解鎖互斥,但他卻不歸任何線程所有。
        #include <pthread.h>
        pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
        int pthread_mutex_destroy(pthread_mutex_t *mutex);
        int pthread_mutex_init(pthread_mutex_t *restrict mutex,
              const pthread_mutexattr_t *restrict attr);
        int pthread_mutex_lock(pthread_mutex_t *mutex);
        int pthread_mutex_trylock(pthread_mutex_t *mutex);
        int pthread_mutex_unlock(pthread_mutex_t *mutex);
        pthread_mutex_init函數創建指針mutex指向的互斥,並且用mutexattr指定的屬性初始化該互斥。
        互斥屬性
        屬性                                                    描述                    備註
        PTHREAD_MUTEX_INITIALIZER                       創建一個快速互斥        調用線程被阻塞直至擁有互斥的線程解鎖爲止
        PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP      創建一個遞歸互斥        不阻塞調用進程,但返回一個出錯代碼EDEADLK
        PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP 創建一個檢錯互斥        成功返回並增加調用線程上鎖的次數,但必須擁有同樣次數的解鎖
        除了使用mutex參數,還可以使用下面的初始化過程靜態創建pthread_mutex_t變量。
        pthread_mutex_t fastmutex = PTHREAD_MUTEX_INITIALIZER;
        pthread_mutex_t recmutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
        pthread_mutex_t errchkmutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;       
 

#include <pthread.h>

#include <stdlib.h>

#include <stdio.h>

#include <unistd.h>

 

int i = 0;

int j = 0;

 

void test1(int * num);

void test2(int * num);

int main(void)

{

    pthread_t pt1, pt2;

   

    if (pthread_create(&pt1, NULL, (void *)test1, (void *)&i))

    {

        perror("Creat pthread test1 error\n");

        exit(EXIT_FAILURE);

    }

    if (pthread_create(&pt2, NULL, (void *)test2, (void *)&j))

    {

        perror("Creat thread  test2 error\n");

        exit(EXIT_FAILURE);

    }

   

    pthread_join(pt1, NULL);

    pthread_join(pt2, NULL);

   

    printf("Total = %d\n",i + j);

   

    return 0;

}

 

void test1(int * num)

{

    int i = 0;

   

    while (i++ < 5)

        printf("In test1 : i = %d\n", (*num)++);

    sleep(5);

    while (0 < i--)

        printf("In test1 -after sleep : i = %d\n",(*num)++);

}

 

void test2(int * num)

{

    int i = 0;

   

    while (i++ < 4)

        printf("In test2 : j = %d\n", (*num)++);

    sleep(8);

       

    while (0 < i--)

        printf("In test2 -after sleep : j = %d\n", (*num)++);

}

 

#include <pthread.h>

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

 

void test1(char * str)

{

    int i = 0;

    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);

    while (i < 5)

        printf("%s : i = %d\n", str, i++);

    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);

    pthread_testcancel();

    puts("Error!");

    sleep(3);

    while (0 < i)

        printf("%s : i = %d\n", str, i--);

}

int main(void)

{

    pthread_t thread1;

 

    pthread_create(&thread1, NULL, (void *)test1, (void *)"thread 1");

 

    pthread_cancel(thread1);

    pthread_join(thread1, NULL);

 

    puts("Back to main");

    return 0;

}

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