Linux系統編程 —執行緒屬性

  • 2020 年 10 月 3 日
  • 筆記

在之前的章節中,我們在調用pthread_create函數創建執行緒時,第二個參數(即執行緒屬性)都是設為NULL,即使用默認屬性。一般情況下,使用默認屬性已經可以解決我們開發過程中的大多數問題。

但是,有時項目中我們對執行緒會有些特殊的要求,比如修改執行緒棧的大小,直接調用執行緒的庫函數無法滿足需求,在這種情況下我們可以直接對執行緒屬性進行設置。

類型pthread_attr_t是一個結構體,主要包括如下屬性:作用域(scope)、棧尺寸(stack size)、棧地址(stack address)、優先順序(priority)、分離的狀態(detached state)、調度策略和參數(scheduling policy and parameters)。

執行緒默認的屬性為非綁定、非分離、預設的堆棧、與父進程同樣級別的優先順序。結構體具體定義如下:

typedef struct

{

​ int etachstate; //執行緒的分離狀態

​ int schedpolicy; //執行緒調度策略

​ struct sched_param schedparam; //執行緒的調度參數

​ int inheritsched; //執行緒的繼承性

​ int cope; //執行緒的作用域

​ size_t guardsize; //執行緒棧末尾的警戒緩衝區大小

​ int stackaddr_set; //執行緒的棧設置

​ size_t stacksize; //執行緒棧的大小

} pthread_attr_t;

主要結構體成員:

​ 1. 執行緒分離狀態:etachstate

​ 2. 執行緒棧大小(默認平均分配):stacksize

​ 3. 執行緒棧警戒緩衝區大小(位於棧末尾):guardsize

執行緒的屬性值不能直接設置,須使用相關函數進行操作。屬性的初始化的函數為pthread_attr_init,這個函數必須在pthread_create函數之前調用。使用完畢之後需調用pthread_attr_destroy函數來釋放資源。

執行緒屬性初始化

函數原型:

int pthread_attr_init(pthread_attr_t *attr);

返回值:

成功:0;失敗:錯誤號。

函數作用:

初始化執行緒屬性;

注意:應先初始化執行緒屬性,再調用pthread_create創建執行緒。

執行緒屬性銷毀

函數原型:

int pthread_attr_destroy(pthread_attr_t *attr);

返回值:

成功:0;失敗:錯誤號

函數作用:

銷毀執行緒屬性所佔用的資源

執行緒的分離狀態

執行緒的分離狀態決定一個執行緒最後終止的時候是以怎樣的方式回收資源。

非分離狀態:執行緒的默認屬性是非分離狀態,這種情況下,執行緒運行結束後,只有當其它執行緒調用pthread_join()函數去回收它時,創建的執行緒才算終止,才能釋放自己佔用的系統資源。

分離狀態:執行緒如果設置為分離狀態,則它將主動與主控執行緒脫離關係,當它自己運行結束了,執行緒也就終止了,馬上釋放系統資源。

設置執行緒分離狀態的函數:

設置執行緒屬性

int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);

獲取程屬性

int pthread_attr_getdetachstate(pthread_attr_t *attr, int *detachstate);

參數:attr:指向一個執行緒屬性的指針

detachstate:執行緒分離狀態

PTHREAD_CREATE_DETACHED(分離執行緒)

PTHREAD _CREATE_JOINABLE(非分離執行緒)

執行緒的棧地址

POSIX.1定義了兩個常量_POSIX_THREAD_ATTR_STACKADDR 和_POSIX_THREAD_ATTR_STACKSIZE檢測系統是否支援棧屬性。也可以給sysconf函數傳遞_SC_THREAD_ATTR_STACKADDR或 _SC_THREAD_ATTR_STACKSIZE來進行檢測。

當進程棧地址空間不夠用時,指定新建執行緒使用由malloc分配的空間作為自己的棧空間。通過pthread_attr_setstack和pthread_attr_getstack兩個函數分別設置和獲取執行緒的棧地址。

設置執行緒的棧地址:

int pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr, size_t stacksize);

成功:0;失敗:錯誤號

獲取執行緒的棧地址:

int pthread_attr_getstack(pthread_attr_t *attr, void **stackaddr, size_t *stacksize);

成功:0;失敗:錯誤號

參數:attr:指向一個執行緒屬性的指針

stackaddr:返回獲取的棧地址

stacksize:返回獲取的棧大小

執行緒的棧大小

當系統中有很多執行緒時,可能需要減小每個執行緒棧的默認大小,防止進程的地址空間不夠用。當執行緒調用的函數會分配很大的局部變數或者函數調用層次很深時,可能需要增大執行緒棧的默認大小。

函數pthread_attr_getstacksize和 pthread_attr_setstacksize可以設置或者獲取執行緒的棧大小。

設置執行緒棧大小:

int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);

成功:0;失敗:錯誤號

獲取執行緒棧大小:

int pthread_attr_getstacksize(pthread_attr_t *attr, size_t *stacksize);

成功:0;失敗:錯誤號

參數:attr:指向一個執行緒屬性的指針

stacksize:返回執行緒的堆棧大小

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

#define SIZE 0x10000

void *th_fun(void *arg)
{
    while (1) 
        sleep(1);
}

int main(void)
{
    pthread_t tid;
    int err, detachstate, i = 1;
    pthread_attr_t attr;
    size_t stacksize;   //typedef  size_t  unsigned int 
    void *stackaddr;

    pthread_attr_init(&attr);       
    pthread_attr_getstack(&attr, &stackaddr, &stacksize);
    pthread_attr_getdetachstate(&attr, &detachstate);

    if (detachstate == PTHREAD_CREATE_DETACHED)   //默認是分離態
        printf("thread detached\n");
    else if (detachstate == PTHREAD_CREATE_JOINABLE) //默認時非分離
        printf("thread join\n");
    else
        printf("thread un known\n");

    /* 設置執行緒分離屬性 */
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

    while (1) {
        /* 在堆上申請記憶體,指定執行緒棧的起始地址和大小 */
        stackaddr = malloc(SIZE);
        if (stackaddr == NULL) {
            perror("malloc");
            exit(1);
        }
        stacksize = SIZE;
        pthread_attr_setstack(&attr, stackaddr, stacksize);   //藉助執行緒的屬性,修改執行緒棧空間大小

        err = pthread_create(&tid, &attr, th_fun, NULL);
        if (err != 0) {
            printf("%s\n", strerror(err));
            exit(1);
        }
        printf("%d\n", i++);
    }

    pthread_attr_destroy(&attr);

    return 0;
}

更多精彩內容,請關注公眾號良許Linux,公眾內回復1024可免費獲得5T技術資料,包括:Linux,C/C++,Python,樹莓派,嵌入式,Java,人工智慧,等等。公眾號內回復進群,邀請您進高手如雲技術交流群。

img


公眾號:良許Linux

有收穫?希望老鐵們來個三連擊,給更多的人看到這篇文章