Linux 線程的屬性 線程池 多線程的創建
線程的屬性
引入
我們設想一個場景,使用pthread_detach時,發現線程早就已經結束了,這時候pthread_detach還能正常發揮清理線程的 獨有空間 的作用嗎?
答案是可以的,但是這難免是一個 程序設計上的一個小缺陷,雖不影響結果,但是總是讓人感到困惑。為了解決這一問題,我們可以在 線程屬性?中進行對應設置。下面我們來學習一下如何操作線程屬性吧!
這里再次提醒,當我們屬性設置了detach或者調用了pthread_detach后,就不可以再使用pthread_join函數了。
介紹
typedef struct
{
????????int etachstate; //線程的分離狀態
????????int schedpolicy; //線程調度策略
????????struct sched_param schedparam; //線程的調度參數
????????int inheritsched; //線程的繼承性
????????int scope; //線程的作用域
????????size_t guardsize; //線程棧末尾的警戒緩沖區大小
????????int stackaddr_set; //線程的棧設置
????????void* stackaddr; //線程棧的位置
????????size_t stacksize; //線程棧的大小
} pthread_attr_t;
可以看到,線程屬性是一個結構體,其中包含的成員也有很多,但查看和修改步驟都大同小異,下面我主要向大家展示 分離狀態 和 棧 屬性的 查看和修改。
線程屬性設置API
初始化線程屬性函數:
int pthread_attr_init(pthread_attr_t *attr);
函數返回值:
????????成功:0;
????????失敗:錯誤號
銷毀線程屬性所占用的資源函數:
int pthread_attr_destroy(pthread_attr_t *attr);
函數返回值:
????????成功:0;
????????失敗:錯誤號
設置線程屬性,分離or非分離
1 int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
獲取程屬性,分離or非分離
1 int pthread_attr_getdetachstate(pthread_attr_t *attr, int *detachstat);
參數:
????????attr:已初始化的線程屬性
????????detachstate: 分離狀態
????????????????PTHREAD_CREATE_DETACHED(分離線程)
????????????????PTHREAD_CREATE_JOINABLE(非分離線程)
線程設置的步驟
????????1、獲取
????????2、修改
????????3、設置
代碼練習
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#define SIZE 128
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;void *stackaddr;// 初始化線程屬性pthread_attr_init(&attr);// 設置線程的屬性值為分離狀態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){perror("pthread_create");_exit(-1);}printf("%d\n", i++);sleep(1);}pthread_attr_destroy(&attr);return 0;
}
代碼運行結果
我們可以看到主線程正常運行,說明子線程,線程已經是 分離狀態了。
在這里,我想向大家引入一下進程池的概念。
在上面這個例子中,大家可以看到我是在堆區 為棧 申請的空間,這樣的好處是,堆區空間較大可以增加一個進程中最大可容納的線程數目,但是堆區再大,也會有被用完的時候,并且這里 線程申請的空間你不釋放,就永遠不會歸還給系統,相當于一塊空間只是用一次,空間資源利用率較低,因此為了提高線程的最大容納數目和提高空間利用率,線程池就這樣誕生了:
線程池
這里我簡單提一下,大家心里有數就行:
我們把在一個區域內,存放著多個線程,我們可以從這個里取線程,但用完需要歸還,這樣當我們取和還的數目近似時,幾乎就可以無限使用;而不是像現在一樣用了不還,只能等到線程回收。并且這個區域還有一個功能是會根據你的任務數量變化去設置區域中的線程的數目。而這個區域就是線程池。
線程池我之后會詳細介紹,這里大家只需知道這個概念即可。
多線程案例
需要實現的功能
輸入線程名,該與線程執行的時間。對應的線程就會執行對應時間長度,并且可以在線程運行期間,加入其他線程,多個線程一起運行。
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{char task_name[32];int time;
} MSG;void *deal_fun(void *arg)
{MSG msg = *(MSG *)arg;int i = 0;for (i = msg.time; i > 0; i--){printf("%s剩余時間%d\n", msg.task_name, i);sleep(1);}return NULL;
}
int main(int argc, char const *argv[])
{while (1){MSG msg;printf("輸入新增的任務名:");fgets(msg.task_name, sizeof(msg.task_name), stdin);msg.task_name[strlen(msg.task_name) - 1] = 0;printf("輸入運行時間:");scanf("%d", &msg.time);getchar(); // 獲取換行符pthread_t tid;pthread_create(&tid, NULL, deal_fun, (void *)&msg);pthread_detach(tid); // 線程分離}return 0;
}
代碼運行結果
結束
代碼重在練習!
代碼重在練習!
代碼重在練習!
今天的分享就到此結束了,希望對你有所幫助,如果你喜歡我的分享,請點贊收藏夾關注,謝謝大家!!!
博客內容源自課堂筆記,因此偏向于教學,適合新人學習 和 大佬復習,感謝你的閱讀!