《UNIX环境高级编程》笔记--线程属性

在之前调用pthread_create函数的例子中,传入的参数都是空指针,而不是指向pthread_attr_t结构的指正,可以使用

pthread_attr_t结构修改线程默认属性,并把这些属性与创建的线程联系起来。可以使用pthread_attr_init函数初始化

pthread_attr_t结构。调用pthread_attr_init后,pthread_attr_t结构所包含的内容就是操作系统现支持的线程所有属性的默认

值,如果要修改其中个别属性的值,需要调用其他的函数,这方面的细节会在后面讨论到。

#include<pthread.h>
int pthread_attr_init(pthread_attr_t *attr);
int pthread_attr_destroy(pthread_attr_t *attr);
//若成功则返回0,否则返回错误编号。

1.分离属性

之前介绍过线程分离的概念,详细可以参见:http://blog.csdn.net/todd911/article/details/17883201。使用pthread_detach

函数让操作系统在线程退出时收回它所占用的资源。可以修改pthread_attr_t结构中的detachstate线程属性。让线程以分离状态

启动。可以使用pthread_attr_setdetachstate函数把线程属性detachstate是指为下面两个合法值之一:

PTHREAD_CREATE_DETACHED:以分离状态启动线程。

PTHREAD_CREATE_JOINABLE:正常启动线程,应用程序可以获取线程的终止状态。

#include <pthread.h>
int pthread_attr_getdetachstate(const *pthread_attr_t *restrict attr, int *detachstate);
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
//成功则返回0,否则返回错误编号。
下面给出了一个以分离状态创建线程的函数:

int makethread(void* (*fn)(void*), void *arg){
	int err;
	pthread_t tid;
	pthread_attr_t attr;
	
	err = pthread_attr_init(&attr);
	if(err != 0){
		return err;
	}
	err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
	if(err == 0 ){
		err = pthread_create(&tid, &attr, fn, arg);
	}
	pthread_attr_destroy(&attr);
	return err;
}

这边没有判断pthread_attr_destroy函数的返回值,一般这个函数不会出错,但是如果确实失败了,清理工作会变得很困难:

必须销毁刚刚创建的线程,而这个线程可能已经运行。忽略pthread_attr_destroy的错误返回可能出现的最坏情况是:如果

pthread_attr_init分配了内存空间,这些空间会被泄漏。


2.栈属性

线程栈属性的查询和修改一般是通过函数pthread_attr_getstack和pthread_attr_setstack来进行。
#include <pthread.h>
int pthread_attr_getstack(const pthread_attr_t *restrict attr, void **restrict stackaddr, size_t *restrict stacksize);
int pthread_attr_setstack(const pthread_attr_t *attr, void *stackaddr, size_t stackszie);
//成功则返回0,否则返回错误编号。
这两个函数可以用于管理stackaddr线程属性,也可以用于管理stacksize线程属性。
对线程来说虚拟地址空间的大小是固定的,进程只有一个栈,所以它的大小通常不是问题,但是对线程来说,同样大小虚拟
地址空间必须被所有的线程栈共享,如果应用程序使用了太多的线程,致使线程栈的累计大小超过了可用的虚拟地址空间。
如果用完了线程栈的虚拟地址空间,可以使用malloc或者mmap来为其他栈分配空间,并用pthread_attr_setstack函数来
改变线程栈位置。线程栈所占内存范围中可寻址的最低地址可以由stackaddr参数指定。

应用程序也可以通过pthread_attr_getstacksize和pthread_attr_setstacksize函数读取或者设置线程属性stacksize。
#include<pthread.h>
int pthread_attr_getstacksize(const pthread_attr_t *restrict attr, size_t *restrict stacksize);
int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
//成功返回0,否则返回错误编号。
如果希望改变栈的默认大小,但又不想自己处理线程栈的分配问题,这时使用pthread_attr_setstacksize函数就非常有用。

3.guardsize属性

线程属性guardsize控制着线程栈末端只有用以避免栈溢出的扩展内存的大小,这个属性默认为PAGESIZE个字节,可以

把guardsize线程属性设置为0,从而不允许属性的这种特性行为发生:在这种情况下不会提供警戒缓冲区。同样地,如果对

线程属性stackaddr做了修改,系统就会假设我们会自己管理栈,并使警戒栈缓冲区机制无效,等同于guardsize线程属性设置

为0.

#include<pthread.h>
int pthread_attr_getguardsize(const phread_attr_t *restrict attr, size_t *restrict guardsize);
int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize);
//成功则返回0,否则返回错误编号。

4.并发度

并发度控制着用户级线程可以映射的内核线程或进程的数目,如果操作系统的实现在内核级的线程和用户级的线程之间保持

一对一的映射,那么改变并发度并不会有什么效果,因为所有的线程都可能被调度到,但是如果操作系统的实现让用户级线程

到内核级线程或进程之前的映射关系是多对一的话,那么在给定时间内增加可运行的用户级线程数,可能会改善性能。

pthread_setconcurrency函数可以用于提示系统,表明希望的并发度。

#include <pthread.h>
int pthread_getconcurrency(void); //返回当前的并发度
int pthread_setconcurrency(int level); //成功则返回0,否则返回错误编号。

pthread_getconcurrency函数返回当前的并发度。如果操作系统当前正控制着并发度(即之前没有调用过set函数),那么该

函数将返回0。

pthread_setconcurrency函数设定的并发度只是对系统的一个提示,系统并不能保证请求的并发度一定会被采用,如果希望系统

自己决定使用什么样的并发度,就将level设置为0,。


注意:上面说到的stack size和guard size都是指unix环境下,在linux环境下,线程是以轻量级进程的概念实现的,所以可能

不适用于上面的说明。

你可能感兴趣的:(《UNIX环境高级编程》笔记--线程属性)