天天看點

Linux線程之屬性(十四)1.線程屬性2.參考代碼

Linux線程之屬性(十四)

  • 1.線程屬性
    • 1.1.主要結構體成員
    • 1.2.線程屬性初始化注意
    • 1.3.初始化線程屬性函數
    • 1.4.銷毀線程屬性所占用的資源函數
    • 1.5.線程分離狀态的函數:設定線程屬性
    • 1.6.線程分離狀态的函數:擷取線程屬性
    • 1.7.設定線程的棧位址
    • 1.8.擷取線程的棧位址
  • 2.參考代碼

1.線程屬性

Linux下線程的屬性是可以根據實際項目需要,進行設定,之前我們讨論的線程都是采用線程的預設屬性,預設屬性已經可以解決絕大多數開發時遇到的問題。 如我們對程式的性能提出更高的要求那麼需要設定線程屬性,比如可以通過設定線程棧的大小來降低記憶體的使用,增加最大線程個數。Linux下線程的屬性是可以根據實際項目需要,進行設定,之前我們讨論的線程都是采用線程的預設屬性,預設屬性已經可以解決絕大多數開發時遇到的問題。 如我們對程式的性能提出更高的要求那麼需要設定線程屬性,比如可以通過設定線程棧的大小來降低記憶體的使用,增加最大線程個數。

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; 
           

1.1.主要結構體成員

  1. 線程分離狀态
  2. 線程棧大小(預設平均配置設定)
  3. 線程棧警戒緩沖區大小(位于棧末尾)
  4. 線程棧最低位址 屬性值不能直接設定,須使用相關函數進行操作,初始化的函數為pthreadattrinit,這個函數必須在pthreadcreate函數之前調用。之後須用pthreadattr_destroy函數來釋放資源。 線程屬性主要包括如下屬性:作用域(scope)、棧尺寸(stack size)、棧位址(stack address)、優先級(priority)、分離的狀态(detached state)、排程政策和參數(scheduling policy and parameters)。預設的屬性為非綁定、非分離、預設的堆棧、與父程序同樣級别的優先級.

1.2.線程屬性初始化注意

應先初始化線程屬性,再pthreadcreate建立線程。

1.3.初始化線程屬性函數

功能:

初始化線程屬性函數。

參數:

attr: 線程屬性結構體指針變量。

傳回值:

成功:0

失敗: 錯誤号。

1.4.銷毀線程屬性所占用的資源函數

功能:

銷毀線程屬性所占用的資源函數。

參數:

attr: 線程屬性結構體指針變量。

傳回值:

成功:0

失敗: 錯誤号。

注意:程的分離狀态 線程的分離狀态決定一個線程以什麼樣的方式來終止自己。  非分離狀态:線程的預設屬性是非分離狀态,這種情況下,原有的線程等待建立的線程結束。隻有當pthreadjoin()函數傳回時,建立的線程才算終止,才能釋放自己占用的系統資源。  分離狀态:分離線程沒有被其他的線程所等待,自己運作結束了,線程也就終止了,馬上釋放系統資源。應該根據自己的需要,選擇适當的分離狀态。

1.5.線程分離狀态的函數:設定線程屬性

功能:

設定線程屬性,分離or非分離。

參數:

attr: 已初始化的線程屬性。

detachstate:分離狀态。

detachstate說明:

PTHREADCREATEDETACHED(分離線程)

PTHREAD CREATEJOINABLE(非分離線程)

傳回值:

成功:0

失敗: 錯誤号。

1.6.線程分離狀态的函數:擷取線程屬性

功能:

設定線程屬性,分離or非分離。

參數:

attr: 已初始化的線程屬性。

detachstate:分離狀态。

detachstate說明:

PTHREADCREATEDETACHED(分離線程)

PTHREAD CREATEJOINABLE(非分離線程)

傳回值:

成功:0

失敗: 錯誤号。

注意:這裡要注意的一點是,如果設定一個線程為分離線程,而這個線程運作又非常快,它很可能在pthreadcreate函數傳回之前就終止了,它終止以後就可能将線程号和系統資源移交給其他的線程使用,這樣調用pthreadcreate的線程就得到了錯誤的線程号。 要避免這種情況可以采取一定的同步措施,最簡單的方法之一是可以在被建立的線程裡調用pthreadcondtimedwait函數,讓這個線程等待一會兒,留出足夠的時間讓函數pthreadcreate傳回。 設定一段等待時間,是在多線程程式設計裡常用的方法。但是注意不要使用諸如wait()之類的函數,它們是使整個程序睡眠,并不能解決線程同步的問題。 線程的棧位址 POSIX.1定義了兩個常量POSIXTHREADATTRSTACKADDR 和POSIXTHREADATTRSTACKSIZE檢測系統是否支援棧屬性。也可以給sysconf函數傳遞SCTHREADATTRSTACKADDR或 _SCTHREADATTRSTACKSIZE來進行檢測。 當程序棧位址空間不夠用時,指定建立線程使用由malloc配置設定的空間作為自己的棧空間。通過pthreadattrsetstack和pthreadattrgetstack兩個函數分别設定和擷取線程的棧位址。

1.7.設定線程的棧位址

功能:

設定線程的棧位址。

參數:

attr: 指向一個線程屬性的指針。

stackaddr:傳回擷取的棧位址。

stacksize:傳回擷取的棧大小 線程的棧大小。

傳回值:

成功:0

失敗: 錯誤号。

1.8.擷取線程的棧位址

功能:

擷取線程的棧位址。

參數:

attr: 指向一個線程屬性的指針。

stackaddr:傳回擷取的棧位址。

stacksize:傳回擷取的棧大小 線程的棧大小。

傳回值:

成功:0

失敗: 錯誤号。

注意:系統中有很多線程時,可能需要減小每個線程棧的預設大小,防止程序的位址空間不夠用,當線程調用的函數會配置設定很大的局部變量或者函數調用層次很深時,可能需要增大線程棧的預設大小。 函數pthreadattrgetstacksize和 pthreadattrsetstacksize提供設定。 int pthreadattrsetstacksize(pthreadattrt *attr, sizet stacksize); 成功:0;失敗:錯誤号 int pthreadattrgetstacksize(pthreadattrt *attr, sizet *stacksize); 成功:0;失敗:錯誤号 參數: attr:指向一個線程屬性的指針 stacksize:傳回線程的堆棧大小

2.參考代碼

//=============================================================================
// File Name    : thread_attr.c
// Author       : FengQQ
//
// Description  : 線程的屬性
// Annotation   : 
//
// Created by FengQQ. 2020-10-04
//=============================================================================
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>

#define SIZE 0x100000

//---------------線程入口函數---------------
void *pthread_callback(void *arg)
{
	while(1)
	{
		sleep(1);	
	}	
}

int main(int argc,char *argv[])
{
	int ret,i;
	pthread_t ptid;
	pthread_attr_t attr;
	size_t stacksize;
	void *stackaddr;
	int detachstate;

	pthread_attr_init(&attr);											//初始化線程屬性
	pthread_attr_getstack(&attr, &stackaddr, &stacksize);				//擷取線程的棧位址
	pthread_attr_getdetachstate(&attr, &detachstate);					//擷取線程屬性
	
	if(detachstate == PTHREAD_CREATE_DETACHED)
	{
		printf("pthread detached...\r\n");
	}
	
	else if(detachstate == PTHREAD_CREATE_JOINABLE)
	{
		printf("pthread join...\r\n");
	}		
	else
	{
		printf("pthread unknown...\r\n");
	}
		
	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);		//設定線程屬性

	while(1)
	{
		stackaddr = malloc(SIZE);										//申請記憶體空間
		if (stackaddr == NULL) 
		{
			printf("malloc failed...\r\n");
			exit(1);
		}
		stacksize = SIZE;
		pthread_attr_setstack(&attr, stackaddr, stacksize);				//設定線程的棧位址
		ret = pthread_create(&ptid, &attr,pthread_callback, NULL);		//建立線程
		if(ret != 0) 
		{
			printf("create new pthread failed...\r\n");
			exit(1);
		}
		
		sleep(1);
		printf("i = %d\n", i++);
	}
	
	pthread_attr_destroy(&attr);										//銷毀線程屬性所占用的資源

	return 0;
}

           

繼續閱讀