线程属性的修改
(1)線程屬性
Linux下線程的屬性是可以根據實際項目需要,進行設置,之前我們討論的線程都是采用線程的默認屬性,默認屬性已經可以解決絕大多數開發時遇到的問題。如我們對程序的性能提出更高的要求那么需要設置線程屬性,比如可以通過設置線程棧的大小來降低內存的使用,增加最大線程個數。
typedef struct
{
int ???????????????????????????? detachstate; //線程的分離狀態
int ????????????????????????????? schedpolicy; ? //線程調度策略
struct sched_param ??? schedparam; ? //線程的調度參數
int ????????????????????????????? inheritsched; //線程的繼承性
int ????????????????????????????? scope; ?????????? //線程的作用域
size_t ???????????????????????? guardsize; ??? //線程棧末尾的警戒緩沖區大小
int?????????????????????????????? stackaddr_set; //線程的棧設置
void* ???????????????????????? stackaddr; ???? //線程棧的位置
size_t ???????????????????????? stacksize; ???? //線程棧的大小?
} pthread_attr_t; ????//加粗的三個成員常用到
ulimit –a命令可以查看進程的屬性,可以看到默認棧大小為8MB(8192KB)。默認時,多個線程的線程棧是均分這個8M空間,如果2個線程,則各為4M。當線程數量太多時,8M不夠用,可以從堆空間(heap)上申請一段內存(malloc),然后把這段內存指定到線程棧里面,從而修改了線程棧的大小。(當然也可以修改進程進程棧空間的大小,使用ulimit命令)
兩個線程棧空間之間的空隙稱為警戒區(guardsize,線程棧空間都相互獨立,不連續),其作用是為了防止線程溢出。可以在線程屬性中設置這個警戒區的大小。關于具體的設置方法,參考APUE.12.3 線程屬性。
主要結構體成員:1. 線程分離狀態(detachstate);2. 線程棧大小(stacksize,默認平均分配);3. 線程棧警戒緩沖區大小(guardsize,位于棧末尾)。
屬性值不能直接設置,須使用相關函數進行操作,初始化的函數為pthread_attr_init,這個函數必須在pthread_create函數之前調用。之后須用pthread_attr_destroy函數來釋放資源。
線程屬性主要包括如下屬性:作用域(scope)、棧尺寸(stack size)、棧地址(stack address)、優先級(priority)、分離的狀態(detached state)、調度策略和參數(scheduling policy and parameters)。默認的屬性為非綁定、非分離、缺省的堆棧、與父進程同樣級別的優先級。
(2)線程屬性初始化和線程屬性的釋放
注意:應先初始化線程屬性,再pthread_create創建線程
初始化線程屬性: int pthread_attr_init(pthread_attr_t *attr);? ?成功:0;失敗:錯誤號
銷毀線程屬性所占用的資源: int pthread_attr_destroy(pthread_attr_t *attr); ?成功:0;失敗:錯誤號
(3)線程的分離狀態
線程的分離狀態決定一個線程以什么樣的方式來終止自己。
非分離狀態(PTHREAD _CREATE_JOINABLE):線程的默認屬性是非分離狀態,這種情況下,原有的線程等待創建的線程結束。只有當pthread_join()函數返回時,創建的線程才算終止,才能釋放自己占用的系統資源。
分離狀態(PTHREAD_CREATE_DETACHED):分離線程沒有被其他的線程所等待,自己運行結束了,線程也就終止了,馬上釋放系統資源。應該根據自己的需要,選擇適當的分離狀態。
線程分離狀態的函數:
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
作用:設置線程屬性,分離or非分離?? 成功:0;失敗:錯誤號
int pthread_attr_getdetachstate(pthread_attr_t *attr, int *detachstate);
作用:獲取程屬性,分離or非分離??? 成功:0;失敗:錯誤號
注意:參數attr必須為已初始化的線程屬性
detachstate:PTHREAD_CREATE_DETACHED(分離線程)、PTHREAD _CREATE_JOINABLE(非分離線程)。
這里要注意的一點是,如果設置一個線程為分離線程,而這個線程運行又非常快,它很可能在pthread_create函數返回之前就終止了,它終止以后就可能將線程號和系統資源移交給其他的線程使用,這樣調用pthread_create的線程就得到了錯誤的線程號。要避免這種情況可以采取一定的同步措施,最簡單的方法之一是可以在被創建的線程里調用pthread_cond_timedwait函數,讓這個線程等待一會兒,留出足夠的時間讓函數pthread_create返回。設置一段等待時間,是在多線程編程里常用的方法。但是注意不要使用諸如wait()之類的函數,它們是使整個進程睡眠,并不能解決線程同步的問題。
(4)線程的棧地址
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:返回獲取的棧大小
(5)線程的棧大小
當系統中有很多線程時,可能需要減小每個線程棧的默認大小,防止進程的地址空間不夠用,當線程調用的函數會分配很大的局部變量或者函數調用層次很深時,可能需要增大線程棧的默認大小。
函數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 <unistd.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <pthread.h>void *tfn(void *arg) {while (1)sleep(1); }int main(void) {pthread_t tid;int ret, count = 1;for (;;) {ret = pthread_create(&tid, NULL, tfn, NULL);if (ret != 0) {printf("pthread_create error: %s\n", strerror(ret));break;}printf("---------%d\n", ++count);}return 0; }//線程屬性控制示例
#include <stdio.h> #include <pthread.h> #include <string.h> #include <stdlib.h> #include <unistd.h>#define SIZE 0x100000void *th_fun(void *arg) {while (1)sleep(1);free(arg); //線程結束之前,釋放malloc分配的堆空間arg=NULL; }int main(void) {pthread_t tid;int err, detachstate, n = 10;pthread_attr_t attr;size_t stacksize, stacksize1; //typedef size_t unsigned int void *stackaddr;pthread_attr_init(&attr); //初始化線程屬性pthread_attr_getstack(&attr, &stackaddr, &stacksize); //默認屬性棧空間pthread_attr_getdetachstate(&attr, &detachstate); //默認屬性棧狀態pthread_attr_getstacksize(&attr, &stacksize1); //默認屬性棧空間printf("The default stackaddr is %#x, and the stacksize is %d.\n",stackaddr,stacksize);printf("The default stacksize is %d.\n",stacksize1);printf("The default detachstate is %d.\n",detachstate);if (detachstate == PTHREAD_CREATE_DETACHED) //默認是分離態printf("thread detached\n");else if (detachstate == PTHREAD_CREATE_JOINABLE) //默認時非分離printf("thread join\n");elseprintf("thread un known\n");/* 設置線程分離屬性 */pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);while (n--) {/* 在堆上申請內存,指定線程棧的起始地址和大小 */stackaddr = (void *)malloc(SIZE);if (stackaddr == NULL) {perror("malloc");exit(1);}stacksize = SIZE;pthread_attr_setstack(&attr, stackaddr, stacksize); //借助線程的屬性,修改線程棧空間大小err = pthread_create(&tid, &attr, th_fun, stackaddr);if (err != 0) {printf("pthread_create error: %s\n", strerror(err));exit(1);}}pthread_attr_destroy(&attr);return 0; }[root@localhost 01_pthread_test]# ./pthrd_attr_change
The default stackaddr is 0, and the stacksize is 0.? //默認未設置
The default stacksize is 8388608.?
The default detachstate is 0.? //0代表非分離態
thread join
總結
- 上一篇: 英雄联盟职业比赛中,如果中途断网或者断电
- 下一篇: NPTL(Native POSIX Th