1. 程式人生 > >linux之執行緒的高階屬性

linux之執行緒的高階屬性

一次性初始化: 用途:  有些事需要且只能執行一次(比如互斥量初始化)。通常當初始化應用程式時,可以比較容易地將其放在main函式中。但當你寫一個庫函式時,就不能在main裡面初始化了,你可以用靜態初始化,但使用一次初始(pthread_once_t)會比較容易些。 用法: 

//首先要定義一個pthread_once_t變數,這個變數要用巨集PTHREAD_ONCE_INIT初始化。
//然後建立一個與控制變數相關的初始化函式

    pthread_once_t once_control = PTHREAD_ONCE_INIT;
    void init_routine( )
    {
         //需要初始化的內容
         ......
    }

//最後,在任何時刻呼叫pthread_once函式。
//在多執行緒程式設計環境下,init_routine()函式僅執行一次,究竟在哪個執行緒中執行是不定的,由核心排程來決定。
int pthread_once(pthread_once_t *once_control, void (*init_routine)(void));

執行緒的屬性:

執行緒的屬性型別:pthread_attr_t

屬性名稱 描述
detachstate   執行緒的分離狀態
guardsize 執行緒棧末尾的警戒區域大小(位元組數)
stacksize 執行緒棧的最低地址
stacksize 執行緒棧的大小(位元組數)

 1、執行緒屬性初始化      int pthread_attr_init(pthread_attr_t *attr);  2、執行緒屬性銷燬      int pthread_attr_destroy(pthread_attr_t *attr);

執行緒的分離屬性:

1、分離屬性的概念         分離一個正在執行的執行緒並不影響它,僅僅是通知當前系統該執行緒結束時,其所屬的資源可以回收。一個沒有被分離的執行緒在終止時會保留它的虛擬記憶體,包括他們的堆疊和其他系統資源,有時這種執行緒被稱為“殭屍執行緒”。建立執行緒時預設是非分離的         如果執行緒具有分離屬性,執行緒終止時會被立刻回收,回收將釋放掉所有線上程終止時未釋放的系統資源和程序資源。包括儲存執行緒返回值的記憶體空間、堆疊、儲存暫存器的記憶體空間等

2、分離屬性的使用方法         如果在建立執行緒的時候就知道不需要了解執行緒的終止狀態,那麼可以修改pthread_attr_t結構體的detachstate屬性,讓執行緒以分離狀態啟動。    

//設定執行緒分離屬性的步驟
//1、定義執行緒屬性變數
      pthread_attr_t   attr 
// 2、初始化attr
    pthread_attr_init(&attr)
//3、設定執行緒的分離狀態屬性
//執行緒的分離屬性有兩種合法值:PTHREAD_CREATE_DETACHED分離的 PTHREAD_CREATE_JOINABLE 非分離的,可連線的        
    int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
//4、建立執行緒
    int pthread_create(&tid, &attr, thread_fun,  NULL)

獲得執行緒的分離狀態屬性

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

執行緒的棧屬性:

1、執行緒的棧大小         對於程序來說,虛擬地址空間的大小是固定的,程序中只有一個棧,因此它的大小通常不是問題。但對執行緒來說,同樣的虛擬地址被所有的執行緒共享。如果應用程式使用了太多的執行緒,致使執行緒棧累計超過可用的虛擬地址空間,這個時候就需要減少執行緒預設的棧大小。另外,如果執行緒分配了大量的自動變數或者執行緒的棧幀太深,那麼這個時候需要的棧要比預設的大。因此就需要修改執行緒棧的屬性來適應具體程式的需要。

>檢查系統是否支援執行緒棧屬性  1)在編譯階段使用    _POSIX_THREAD_ATTR_STACKADDR 和 _POSIX_THREAD_ATTR_STACKSIZE符號 來檢查系統是否支援執行緒棧屬性,這些巨集定義在/usr/include/bits/posix_opt.h   2)在執行階段把 _SC_THREAD_ATTR_STACKADD和 _SC_THREAD_THREAD_ATTR_STACKSIZE 傳遞給sysconf函式檢查系統對執行緒棧屬性的支援。

如果用完了虛擬地址空間,可以使用malloc或者mmap來為其他棧分配空間,並修改棧的位置。     >修改棧屬性          int pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr, size_t   stacksize);     >獲取棧屬性          int pthread_attr_getstack(pthread_attr_t *attr, void **stackaddr, size_t * stacksize);

也可以單獨獲取或者修改棧的大小,而不去修改棧的地址。棧大小設定,不能小於PTHREAD_STACK_MIN(需要標頭檔案limit.h)      >修改棧大小          int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);      >獲取棧大小          int pthread_attr_getstacksize(pthread_attr_t *attr, size_t *stacksize);

2、棧尾警戒區         執行緒屬性guardsize控制著執行緒棧末尾以後用以避免棧溢位的擴充套件記憶體的大小,這個屬性預設是PAGESIZE個位元組。你可以把它設為0,這樣就不會提供警戒緩衝區。同樣的,如果你修改了stackaddr,系統會認為你自己要管理棧,警戒緩衝區會無效

        1)、設定guardsize                 int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize);         2)、獲取guardsize                  int pthread_attr_getguardsize(pthread_attr_t *attr, size_t *guardsize);

例項:

#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
#include<limits.h>
pthread_attr_t attr;
void *thread_1(void * arg)
{
	long signed int  stacksize;
#ifdef _POSIX_THREAD_ATTR_STACKSIZE
	pthread_attr_getstacksize(&attr,&stacksize);
	printf("thread1:  default stacksize is %ld\n",stacksize);

	pthread_attr_setstacksize(&attr,100000);
	pthread_attr_getstacksize(&attr,&stacksize);
	printf("thread1: personic stacksize is %ld\n",stacksize);
	
	pthread_attr_setstacksize(&attr,PTHREAD_STACK_MIN);
	pthread_attr_getstacksize(&attr,&stacksize);
	printf("thread1:  minimum stacksize is %ld\n",stacksize);
#endif
	printf("I am thread1\n");
	return (void *)1;
}

void *thread_2(void * arg)
{
	printf("I am thread2\n");
	return (void *)2;
}

int main(int argc,char *argv[])
{
	pthread_t tid1,tid2;
	int err1,err2;
	pthread_attr_init(&attr);
	pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
//#ifdef _POSIX_THREAD_ATTR_STACKSIZE
//	pthread_attr_setstacksize(&attr,PTHREAD_STACK_MIN);
//#endif
	err1 = pthread_create(&tid1,&attr, thread_1,NULL);
	err2 = pthread_create(&tid2,NULL, thread_2,NULL);
	if(err1||err2)
	{
		printf("create thread fail\n");
		return -1;
	}
	printf("thread1 return value is %d\n",pthread_join(tid1,NULL));
	printf("thread2 return value is %d\n",pthread_join(tid2,NULL));
	pthread_attr_destroy(&attr);
	return 0;
}
執行結果:
[email protected]:~/my_share/pthread$ ./a.out
thread1 return value is 22
thread1:  default stacksize is 8388608
thread1: personic stacksize is 100000
thread1:  minimum stacksize is 16384
I am thread1
I am thread2
thread2 return value is 0