《UNIX环境高级编程》笔记 第十二章-线程控制

1. 线程限制

UNIX操作系统对于线程操作有一些限制。如下图所示,可以通过sysconf函数进行查询

在这里插入图片描述

2. 线程属性

2.1 线程属性概念

对于与线程相关的对象类型,一般都有一个属性类型与之关联(如线程和线程属性关联、互斥量和互斥量属性关联):

  • 有一个初始化属性对象的函数,把属性设置为默认值
  • 有一个销毁属性对象的函数,即释放属性对象资源
  • 一个属性对象可以代表多个属性。属性对象对应用程序不透明,因此应用程序不需要了解属性对象结构实现细节,而是通过指定函数与之交互。
  • 属性对象中的每个属性都有一个设置属性值的函数,还有一个获取属性值的函数
2.2 初始化和反初始化pthread_attr_t

在上一章中,通过pthread_create函数创建线程,其中pthread_attr_t是线程属性对象。如果要设置线程为默认属性,则该参数设为NULL。

可以通过pthread_attr_t结构修改线程属性,通过pthread_attr_init函数初始化pthread_attr_t为默认属性值。通过pthread_attr_destroy函数销毁线程属性对象

 int pthread_attr_init(pthread_attr_t *attr);
 int pthread_attr_destroy(pthread_attr_t *attr);

线程属性包括以下几种(部分):

属性名称 说明
detachstate 线程的分离状态属性
guardsize 线程栈末尾的警戒缓冲区大小(字节)
stackaddr 线程栈的最低地址
stacksize 线程栈的最小长度(字节数)
2.3 线程的分离状态属性:

使用pthread_attr_setdetachstate函数设置线程属性对象的detachstate属性:

  • PTHREAD_CREATE_DETACHED以分离(detach)状态启动线程
  • PTHREAD_CREATE_JOINABLE(默认)正常启动线程,应用程序可以获取线程的终止状态(通过pthread_join函数)

通过pthread_attr_getdetachstate函数获取当前的detachstate线程属性

int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate);
2.4 线程栈属性(stackaddr stacksize)

可以通过sysconf(_SC_THREAD_ATTR_STACKADDR)sysconf(_SC_THREAD_ATTR_STACKSIZE)来检查系统对线程栈属性的支持情况。

2.4.1 stackaddr

使用函数pthread_attr_getstack和pthread_attr_setstack对线程栈属性进行获取/设置(即获取/设置线程栈的最低地址和大小)

int pthread_attr_setstack(pthread_attr_t *attr,void *stackaddr, size_t stacksize);
int pthread_attr_getstack(const pthread_attr_t *attr,void **stackaddr, size_t *stacksize);

对于进程来说,虚拟地址空间大小是固定的(对于32位的操作系统,虚拟地址空间的大小为2^32B即0~4GB的虚拟地址空间),因为进程中只有一个栈,所以它的大小通常不是问题。

但是对于线程来说,同样大小的虚拟地址空间必须被所有的线程栈共享。如果应用程序使用很多线程,以至于这些线程栈的累计大小超过了可用的虚拟地址空间,就需要减少默认的线程栈大小

如果线程调用的函数分配了大量的自动变量,或者调用的函数涉及许多很深的栈帧(如递归),那么需要的栈大小可能要比默认的大

如果线程栈的虚拟地址空间都用完了,可以使用malloc或mmap来为可替代的栈分配空间,并用pthread_attr_setstack函数来改变新建线程的栈位置。stackaddr参数指定的地址用作线程栈的内存范围中最低可寻址地址,stacksize为分配的缓冲区字节数

注意,stackaddr线程属性被定义为栈的最低内存地址,但这并不一定是栈的开始位置:如果进程内存空间中栈是从高地址向低地址方向增长的,那么stackaddr将是栈的结尾地址而非开始地址。

2.4.2 stacksize

通过pthread_attr_getstacksize和pthread_attr_setstacksize读取/设置线程属性stacksize

int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
int pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize);

如果希望改变默认的栈大小,但是不想自己处理线程栈的分配问题(向pthread_attr_setstack那样自己设置线程栈空间),可以使用这个函数

注意stacksize不能小于PTHREAD_STACK_MIN限制(见1)

2.5 线程栈末尾的警戒缓冲区大小属性

guardsize线程属性控制着线程栈末尾之后用以避免栈溢出的扩展内存大小

这个属性默认值由具体实现来定义,常用值时系统页大小(如4KB)。

可以将guardsize线程属性设置为0,不允许属性的这种行为发生:此时不提供警戒缓冲区;同样,如果调用pthread_attr_setstack修改线程stackaddr属性,系统就认为我们自己管理栈,因此警戒缓冲区机制无效,等同于将guardsize设为0

int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize);
int pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize);

注意,如果修改了guardsize线程属性,操作系统可能会把它取为页的整数倍大小。

如果线程的栈指针溢出到警戒缓冲区中,应用程序可能通过信号接收到出错信息

2.6 补充:栈空间

可以通过ulimit命令查看进程默认栈大小:可见栈默认大小是8MB

$ ulimit -a
core file size          
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值