12.3 线程属性

	(1)线程属性初始化与销毁
		int pthread_attr_init(pthread_attr_t *attr);		
		int pthread_attr_destroy(pthread_attr_t *attr);		
			1.pthread_attr_init对象对属性对象的内存空间时动态分配的
			2.pthread_attr_destroy函数会释放动态分配的内存
			3.pthread_attr_destroy函数会用无效的值初始化attr对象
	(2)线程属性
		名称						描述		
		datachstate			线程的分离状态属性
		guardsize			线程栈末尾的警戒缓冲区大小(字节数)
		stackaddr			线程栈的最低地址
		stacksize			线程栈的最小长度(字节数)
		
	(3)设置/获取线程的分离状态属性
		pthread_attr_getdetachstatte(const pthread_attr_t *attr, int *detachstate);
		pthread_attr_setdetachstatte(const pthread_attr_t *attr, int *detachstate);
			detachstate为以下两个值:
				PTHREAD_CREATE_DETACHED	// 创建分离线程
				PTHREAD_CREATE_JOINABLE	// 创建可回收线程
		
	(4)线程栈属性
		注意:在编译阶段应该使用下面两个宏来检测系统是否支持线程栈属性,也可以将下面两个宏传给sysconf函数来检查
			_POSIX_THREAD_ATTR_STACKADDR
			_POSIX_THREAD_ATTR_STACKSIZE
		
		(1)概述
			1.对进程来说,一个进程只有一个栈(虚地址空间)。进程栈的大小通常不是问题
			2.对线程来说,多个线程共享进程栈空间。
				每个线程瓜分进程栈的一部分来作为自己的线程栈,而不是混合一起使用。
			3.如果创建的线程过多,线程栈总数超过了进程的栈地址空间,就需要减小默认的线程栈的大小。
			4.如果单个线程需要使用的栈空间超过了默认大小,就需要为线程分取更多的空间。
			
		(2)获取和设置线程栈的地址空间
			int pthread_attr_getstack(const pthread_attr_t *attr, void **stackaddr, size_t *stacksize);
			int pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr, size_t stacksize);
		
			[1] 当进程栈的虚地址空间被线程用完了时,新线程需要分配新的空间来作为线程的栈空间。
				1.新分配的地址空间必须与“系统页地址”对齐
					可通过下面的函数来分配:
					 posix_memalign(&sp, sysconf(_SC_PAGESIZE), stack_size)
				2.通过pthread_attr_setstack函数来设置线程栈的地址空间
					stackaddr:  1.新建线程栈的最低可寻址地址, 该地址应与系统的页地址对齐
								2.栈由下往上增长时, stackaddr表示栈顶未知; 反之为栈底位置。
					stacksize:线程栈的大小
					
		(3)获取和设置线程栈的大小
				如果只希望改变默认的线程栈大小,但是又不想自己处理线程栈的空间分配问题时,调用pthread_attr_setstacksize函数进行测试。
				int pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize);
					// 获取attr中配置的栈大小,并保存到stacksize中
					注意: 该函数并不是获取调用线程的栈大小
				int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
					// 将stacksize指示的线程栈大小设置到stacksize中。
					注意: 该函数并不是设置调用线程的栈大小
						
		(4)获取指定线程thread的属性
			int pthread_getattr_np(pthread_t thread, pthread_attr_t *attr);
				注意: 该函数是非GUN标准函数的扩展			
						
		(5)设置/获取线程栈末尾之后	用以避免栈溢出的扩展内存的大小			
			int pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize);
			int pthread_attr_setguardsize(const pthread_attr_t *attr, size_t guardsize);
			注意: 1.如果guardsize被改变,操作系统可能会把它取为页大小的整数倍
				  2.如果线程的栈溢出到警戒区域,应用程序就可能通过信号接收到出错信息	

测试代码:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <fcntl.h>
#include <assert.h>
#include <sys/wait.h>
#include <sys/acct.h>
#include <errno.h>
#include <sys/times.h>
#include <pthread.h>
#include <signal.h>



void *pstart(void *arg)
{
	
	return (void *)0;
}

int mypthread_attr_setdetachstate(pthread_attr_t *attr)
{
	// int joinable 	= PTHREAD_CREATE_JOINABLE;
	return pthread_attr_setdetachstate(attr, PTHREAD_CREATE_DETACHED);
}

int mypthread_attr_getdetachstate(const pthread_attr_t *attr)
{
	//int detachstate = PTHREAD_CREATE_DETACHED;
	int joinable;
	int re= pthread_attr_getdetachstate(attr, &joinable);
	if (re !=0)
		return -1;
	else {
		if (joinable == PTHREAD_CREATE_DETACHED)
			printf("attr==PTHREAD_CREATE_DETACHED\n");
		else if (joinable == PTHREAD_CREATE_JOINABLE)
			printf("attr==PTHREAD_CREATE_JOINABLE\n");
		else
			return -1;
	}
	return re;
}

void *start_test_stacksize(void *arg)
{
	pthread_attr_t attr;
	size_t stacksize;
	
	pthread_attr_init(&attr);
	pthread_getattr_np(pthread_self(), &attr); 		// 获取当前线程的属性
	pthread_attr_getstacksize(&attr, &stacksize);	// 读取attr中线程栈的大小
	printf("start_test_stacksize: stacksize = %lu\n", stacksize); // 4M=4198400
	return (void *)0;
}
// 测试线程栈大小设置
void threadattr_stacksize_test()
{
	static pthread_attr_t attr_4m;
	size_t stacksize;
	
	pthread_t tid1;
	// 获取线程栈的大小
	pthread_attr_init(&attr_4m);

	if (pthread_attr_setstacksize(&attr_4m, 4*1024 *1024) !=0 )	// 设置attr里的线程栈大小为4M=4198400
	{
		perror("ERROR: pthread_attr_setstacksize\n");
		exit(-1);
	}
	
	pthread_attr_getstacksize(&attr_4m, &stacksize);
	printf("threadattr_stacksize_test: stacksize = %lu\n", stacksize); //attr: 8388608=8M(默认大小)
	//PTHREAD_STACK_MIN
	pthread_create(&tid1, &attr_4m, start_test_stacksize,NULL);
	

	//pthread_attr_destroy(&attr);

}


// 测试线程栈空间配置

void *start_test_stack(void *arg)
{
	pthread_attr_t attr;
	size_t stacksize;
	void *stackaddr;
	
	pthread_attr_init(&attr);
	pthread_getattr_np(pthread_self(), &attr); 					// 获取当前线程的属性


	pthread_attr_getstack(&attr, &stackaddr, &stacksize);				// 读取attr中线程栈的大小
	printf("start_test_stack: stackaddr=%p, stacksize =%lu\n", stackaddr, stacksize); 	// pagesize=4194304=4M

	return (void *)0;
}

void threadattr_stack_test()
{
	static void *sp = NULL;
	static pthread_attr_t attr_pages; // 线程栈
	static pthread_t tid2;
	int stacksize;
	int ret;
	
	pthread_attr_init(&attr_pages);
	long int pagesize = sysconf(_SC_PAGESIZE);	// 系统页地址大小
	printf("pagesize = %ld\n", pagesize);		// 4096
	stacksize = 4*1024 *1024;					// 4M

	
	// pthread_attr_setstack函数要求线程栈开始地址为页地址的整数倍
	ret = posix_memalign(&sp, pagesize, stacksize);	// 按页地址对其, 大小为4194304
	if (ret != 0){
		printf("ERROR: posix_memalign\n");
		exit(0);
	}
	else
		printf("posix_memalign() allocated at %p\n", sp);
	
	if (pthread_attr_setstack(&attr_pages, sp, stacksize) != 0)
	{
		perror("ERROR: pthread_attr_setstack\n");
		exit(-1);
	}
	pthread_create(&tid2, &attr_pages, start_test_stack, NULL);
}


void *start_test_guardsize(void *arg)
{
	pthread_attr_t attr;
	size_t guardsize;
	
	pthread_attr_init(&attr);
	pthread_getattr_np(pthread_self(), &attr); 					// 获取当前线程的属性

	pthread_attr_getguardsize(&attr, &guardsize);				// 读取attr中线程栈末尾警戒区域的大小
	printf("start_test_guardsize: guardsize =%lu\n", guardsize); 	 12288 = 12K
	return (void *)0;
}

void threadattr_guardsize_test()
{
	static pthread_attr_t attr; // 线程栈
	static pthread_t tid3;
	int guardsize;
	
	long int pagesize = sysconf(_SC_PAGESIZE);	// 系统页地址大小=4096
	guardsize = pagesize *3; // 4096*3 = 12k, 必须为页地址的整数倍


	pthread_attr_init(&attr);
	if (pthread_attr_setguardsize(&attr, guardsize) != 0)
	{
		perror("ERROR: pthread_attr_setguardsize\n");
		exit(-1);
	}
	pthread_create(&tid3, &attr, start_test_guardsize, NULL); 

}

int main(int argc, char **argv)
{
#if 1
	// 1. 设置/获取线程的分离状态属性
	pthread_attr_t attr;
	int error;
	pthread_t tid;
	pthread_attr_init(&attr);
	mypthread_attr_getdetachstate(&attr);	// PTHREAD_CREATE_JOINABLE
	mypthread_attr_setdetachstate(&attr);
	mypthread_attr_getdetachstate(&attr);	// PTHREAD_CREATE_DETACHED
#endif
	// 判断系统是否支持线程栈操作
#if defined(_POSIX_THREAD_ATTR_STACKADDR) || defined(_POSIX_THREAD_ATTR_STACKADDE)
	printf("The system supports thread stack propertie\n");

	// 2. 测试仅仅设置/获取线程栈的大小,不处理线程栈的地址空间分配问题
	threadattr_stacksize_test();
	// 3. 测试线程栈的地址空间分配和设置和获取
	threadattr_stack_test();

	// 4. 设置和获取线程栈的临界区域
	threadattr_guardsize_test();
	
#else
	printf("ERROR: The system cant't supports thread stack propertie\n");
#endif
	pause();
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值