執行緒建立的函式及應用小結

Rice_rice發表於2024-06-02

程序是計算機分配資源的基本單位,執行緒是cpu排程的基本單位

執行緒基本概念:

LWP:light weight process 輕量級的程序。建立執行緒的底層函式和程序一樣,都是clone,因此執行緒的本質仍是程序(在linux環境下)

與程序相比,執行緒有獨立的TCB結構體(類似於程序的PCB),但沒有獨立的地址空間(共享),類似於合租與獨居。

檢視執行緒號(LWP,不是TID)可以用下述命令:

ps -Lf xxx(PID)

執行緒建立相關函式

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
//=================================屬性設定按需要採用,若普通情況可以不用設定===============//
pthread_attr_t attr;                                // 定義執行緒的屬性變數
int pthread_attr_init(pthread_attr_t *attr);        // 初始化屬性變數
int pthread_attr_setXXX(pthread_attr_t *attr, ...); // 設定屬性變數的值
//此處僅列舉常用的//
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate); // 設定/獲得執行緒的分離屬性
int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate);
int pthread_attr_setinheritsched(pthread_attr_t *attr, int inheritsched); // 設定/獲得是否繼承建立者的排程策略
int pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inheritsched);
int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy); // 設定/獲得排程策略
int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy);
int pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param); // 設定/獲得執行緒的靜態優先順序
int pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *param);
//=================================上述屬性設定按需要採用,若普通情況可以不用設定===============//

int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);
// 建立執行緒,此處void *(*start_routine)(void *)函式指標指向的函式,void *arg作為其引數,並且需要採用值傳遞,如果資料型別不同需要強轉
int pthread_detach(pthread_t thread); // 如果沒有設定執行緒的分離屬性,可以用此函式強制設為分離屬性,防止執行緒結束後變為殭屍程序,無法釋放資源,而且不能再用 pthread_join等待回收該程序的資源

pthread_t pthread_self(void);         // 建立成功後,可以線上程中使用,獲取當前執行緒的tid
void pthread_exit(void *retval);      // 退出執行緒,並得到返回值retval
int pthread_cancel(pthread_t thread); // 給指定執行緒傳送一個取消的請求
int pthread_setcancelstate(int state, int *oldstate);
// 設定執行緒的取消狀態:PTHREAD_CANCEL_ENABLE 可取消; PTHREAD_CANCEL_DISABLE 不可取消
int pthread_setcanceltype(int type, int *oldtype);
// 設定執行緒的取消型別:PTHREAD_CANCEL_DEFERRED 延時響應; PTHREAD_CANCEL_ASYNCHRONOUS 立即響應。

int pthread_join(pthread_t thread, void **retval); // 接合指定已結束或者待結束的執行緒,並得到返回狀態值;如果指定的執行緒還在執行,將會阻塞等待。

應用例項

char *retval = "byebye!\n"; // 假設為共享資源
pthread_mutex_t m;          // 定義互斥鎖

void handler(void *arg)
{
    pthread_mutex_unlock(&m);
}

void *child_thread(void *arg)
{

    while (1)
    {
        pthread_cleanup_push(handler, NULL); // 上鎖前,需要將handler函式壓入執行緒取消處理的棧中,以防止該子程序在執行的中途被取消,造成死鎖
        pthread_mutex_lock(&m);
        printf("Child thread obtain the mutex:%s\n", retval);
        pthread_mutex_unlock(&m);
        pthread_cleanup_pop(0); // 解鎖後,將handler從棧中彈出,不執行
        sleep(2);
    }
}

int main()
{
    pthread_mutex_init(&m, NULL);

    pthread_t tidofparent = pthread_self(); // 接收主執行緒的tid值。
    printf("parent's tid:%ld\n", tidofparent);
    printf("parent's tid:%ld\n", sizeof(int));

    pthread_t tid;
    pthread_create(&tid, NULL, child_thread, NULL); // 新建子執行緒
    // pthread_detach(tid); 讓執行緒“自立門戶”,結束後資源自動回收,此處與pthread_cancel和pthread_join衝突,
    sleep(5);
    pthread_cancel(tid); // 5秒後,向子執行緒傳送取消的請求

    // 待子執行緒被取消後,鎖被handler自動釋放,可以繼續加互斥鎖,對公共資源進行操作
    pthread_mutex_lock(&m);
    retval = "I'm main pthread!\n";
    printf("Now I botain the mutex:%s\n", retval);
    pthread_mutex_unlock(&m);
    /*
    void *p;
    pthread_join(tid, &p); // 如果沒有采用pthread_cancel(tid)取消子程序,這部分將會阻塞等待子執行緒結束,接受子執行緒的返回值並列印
    printf("子執行緒的返退出回值:%s\n", (char *)p);
*/
    return 0;
}

注意事項

1.主執行緒退出也可以用pthread_exit(),其他子執行緒照樣執行不受影響。但如果主執行緒執行了return/exit等語句,或者子執行緒用exit,會導致整個程序退出。

2.避免執行緒程式設計殭屍程序的三種方法:

  • int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate) 提前設定分離屬性
  • int pthread_detach(pthread_t thread);子執行緒建立後強制設定分離屬性
  • 線上程結束後利用pthread_join()進行接合。

3.malloc 和mmap 申請的記憶體可以被其他子執行緒釋放,因為申請出來的都是共享堆地址。

4.訊號語義複雜,儘量避免和執行緒機制混用。

相關文章