线程属性(多线程编程笔记)

线程属性

前篇介绍了使用缺省属性创建线程的基本原理。本章论述如何在创建线程时设置
属性。
注– 只有pthreads 使用属性和取消功能。本章中介绍的API 仅适用于POSIX 线程。除此
之外,Solaris 线程和pthreads 的功能大致是相同的。

属性对象

通过设置属性,可以指定一种不同于缺省行为的行为。使用pthread_create(3C)创建
线程时,或初始化同步变量时,可以指定属性对象。缺省值通常就足够了。
属性对象是不透明的,而且不能通过赋值直接进行修改。系统提供了一组函数,用于
初始化、配置和销毁每种对象类型。
初始化和配置属性后,属性便具有进程范围的作用域。使用属性时最好的方法即是在
程序执行早期一次配置好所有必需的状态规范。然后,根据需要引用相应的属性对
象。
使用属性对象具有两个主要优点。
■ 使用属性对象可增加代码可移植性。
即使支持的属性可能会在实现之间有所变化,但您不需要修改用于创建线程实体的
函数调用。这些函数调用不需要进行修改,因为属性对象是隐藏在接口之后的。
如果目标系统支持的属性在当前系统中不存在,则必须显式提供才能管理新的属
性。管理这些属性是一项非常容易的移植任务,因为只需在明确定义的位置初始化
属性对象一次即可。
■ 应用程序中的状态规范已被简化。

例如,假设进程中可能存在多组线程。每组线程都提供单独的服务。每组线程都有
各自的状态要求。
在应用程序执行初期的某一时间,可以针对每组线程初始化线程属性对象。以后所
有线程的创建都会引用已经为这类线程初始化的属性对象。初始化阶段是简单和局
部的。将来就可以快速且可靠地进行任何修改。
在进程退出时需要注意属性对象。初始化对象时,将为该对象分配内存。必须将此内
存返回给系统。pthreads 标准提供了用于销毁属性对象的函数调用。

初始化属性

请使用pthread_attr_init(3C)将对象属性初始化为其缺省值。存储空间是在执行期间
由线程系统分配的。

pthread_attr_init 语法

int pthread_attr_init(pthread_attr_t *tattr);
#include 
pthread_attr_t tattr;
int ret;
/* initialize an attribute to the default value */
ret = pthread_attr_init(&tattr); 

表1 给出了属性(tattr) 的缺省值。

属性 结果
scope PTHREAD_SCOPE_PROCESS 新线程与进程中的其他线程发生竞争。
detachstate PTHREAD_CREATE_JOINABLE 线程退出后,保留完成状态和线程ID。
stackaddr NULL 新线程具有系统分配的栈地址。
stacksize 0 新线程具有系统定义的栈大小。
priority 0 新线程的优先级为0。
inheritsched PTHREAD_EXPLICIT_SCHED 新线程不继承父线程调度优先级。
schedpolicy SCHED_OTHER 新线程对同步对象争用使用Solaris 定义的固定优先级。线程将一直运行,直到被抢占或者直到线程阻塞或停止为止。

pthread_attr_init 返回值
pthread_attr_init()成功完成后将返回零。其他任何返回值都表示出现了错误。如果
出现以下情况,该函数将失败并返回对应的值。
ENOMEM
描述: 如果未分配足够的内存来初始化线程属性对象,将返回该值。

销毁属性

请使用pthread_attr_destroy(3C) 删除初始化期间分配的存储空间。属性对象将会无
效。

pthread_attr_destroy语法

int pthread_attr_destroy(pthread_attr_t *tattr);
#include 
pthread_attr_t tattr;
int ret;
/* destroy an attribute */
ret = pthread_attr_destroy(&tattr);

pthread_attr_destroy返回值
pthread_attr_destroy()成功完成后将返回零。其他任何返回值都表示出现了错误。如
果出现以下情况,该函数将失败并返回对应的值。
EINVAL
描述: 指示tattr 的值无效。

设置分离状态

如果创建分离线程(PTHREAD_CREATE_DETACHED),则该线程一退出,便可重用其线程ID
和其他资源。如果调用线程不准备等待线程退出,请使用pthread_attr_setdetachstate(3C)

pthread_attr_setdetachstate(3C) 语法

int pthread_attr_setdetachstate(pthread_attr_t *tattr,int detachstate);
#include 
pthread_attr_t tattr;
int ret;
/* set the thread detach state */
ret = pthread_attr_setdetachstate(&tattr,PTHREAD_CREATE_DETACHED); 

如果使用PTHREAD_CREATE_JOINABLE创建非分离线程,则假设应用程序将等待线程完
成。也就是说,程序将对线程执行pthread_join()
无论是创建分离线程还是非分离线程,在所有线程都退出之前,进程不会退出。

注– 如果未执行显式同步来防止新创建的分离线程失败,则在线程创建者从
pthread_create()返回之前,可以将其线程ID 重新分配给另一个新线程。
非分离线程在终止后,必须要有一个线程用join 来等待它。否则,不会释放该线程的
资源以供新线程使用,而这通常会导致内存泄漏。因此,如果不希望线程被等待,请
将该线程作为分离线程来创建。

示例1创建分离线程

#include 
pthread_attr_t tattr;
pthread_t tid;
void *start_routine;
void arg
int ret; 

/* initialized with default attributes */
ret = pthread_attr_init (&tattr);
ret = pthread_attr_setdetachstate (&tattr,PTHREAD_CREATE_DETACHED);
ret = pthread_create (&tid, &tattr, start_routine, arg); 

pthread_attr_setdetachstate 返回值
pthread_attr_setdetachstate() 成功完成后将返回零。其他任何返回值都表示出现了
错误。如果出现以下情况,该函数将失败并返回对应的值。
EINVAL
描述: 指示detachstate 或tattr 的值无效。

获取分离状态

请使用pthread_attr_getdetachstate(3C) 检索线程创建状态(可以为分离或连接)。

pthread_attr_getdetachstate 语法

int pthread_attr_getdetachstate(const pthread_attr_t *tattr,
        int *detachstate)
#include 
pthread_attr_t tattr;
int detachstate;
int ret;

/* get detachstate of thread */
ret = pthread_attr_getdetachstate (&tattr, &detachstate); 

pthread_attr_getdetachstate返回值
pthread_attr_getdetachstate()成功完成后将返回零。其他任何返回值都表示出现了
错误。如果出现以下情况,该函数将失败并返回对应的值。
EINVAL
描述: 指示detachstate 的值为NULL 或tattr 无效。

设置栈溢出保护区大小

pthread_attr_setguardsize(3C)可以设置attr 对象的guardsize。
pthread_attr_setguardsize(3C)语法

#include 
int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize); 

出于以下两个原因,为应用程序提供了guardsize 属性:
■ 溢出保护可能会导致系统资源浪费。如果应用程序创建大量线程,并且已知这些线
程永远不会溢出其栈,则可以关闭溢出保护区。通过关闭溢出保护区,可以节省系
统资源。
■ 线程在栈上分配大型数据结构时,可能需要较大的溢出保护区来检测栈溢出。
guardsize 参数提供了对栈指针溢出的保护。如果创建线程的栈时使用了保护功能,则
实现会在栈的溢出端分配额外内存。此额外内存的作用与缓冲区一样,可以防止栈指
针的栈溢出。如果应用程序溢出到此缓冲区中,这个错误可能会导致SIGSEGV 信号被发
送给该线程。

如果guardsize 为零,则不会为使用attr 创建的线程提供溢出保护区。如果guardsize 大
于零,则会为每个使用attr 创建的线程提供大小至少为guardsize 字节的溢出保护区。
缺省情况下,线程具有实现定义的非零溢出保护区。
允许合乎惯例的实现,将guardsize 的值向上舍入为可配置的系统变量PAGESIZE 的倍
数。请参见sys/mman.h 中的PAGESIZE。如果实现将guardsize 的值向上舍入为PAGESIZE
的倍数,则以guardsize(先前调用pthread_attr_setguardsize()时指定的溢出保护区
大小)为单位存储对指定attr 的pthread_attr_getguardsize()的调用。

pthread_attr_setguardsize 返回值
如果出现以下情况,pthread_attr_setguardsize() 将失败:
EINVAL
描述: 参数attr 无效,参数guardsize 无效,或参数guardsize 包含无效值。

获取栈溢出保护区大小

pthread_attr_getguardsize(3C) 可以获取attr 对象的guardsize。
pthread_attr_getguardsize语法

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

允许一致的实现将guardsize 中包含的值向上舍入为可配置系统变量PAGESIZE 的倍数。
请参见sys/mman.h 中的PAGESIZE。如果实现将guardsize 的值向上舍入为PAGESIZE的倍
数,则以guardsize(先前调用pthread_attr_setguardsize()时指定的溢出保护区大
小)为单位存储对指定attr 的pthread_attr_getguardsize()的调用。

pthread_attr_getguardsize 返回值
如果出现以下情况,pthread_attr_getguardsize()将失败:
EINVAL
描述: 参数attr 无效,参数guardsize 无效,或参数guardsize 包含无效值。

设置范围

请使用pthread_attr_setscope(3C)建立线程的争用范围(PTHREAD_SCOPE_SYSTEM
PTHREAD_SCOPE_PROCESS)。使用PTHREAD_SCOPE_SYSTEM时,此线程将与系统中的所有
线程进行竞争。使用PTHREAD_SCOPE_PROCESS 时,此线程将与进程中的其他线程进行竞
争。
注– 只有在给定进程中才能访问这两种线程类型。

pthread_attr_setscope语法
int pthread_attr_setscope(pthread_attr_t *tattr,int scope);

#include 
pthread_attr_t tattr;
int ret;
/* bound thread */
ret = pthread_attr_setscope(&tattr, PTHREAD_SCOPE_SYSTEM);
/* unbound thread */
ret = pthread_attr_setscope(&tattr, PTHREAD_SCOPE_PROCESS); 

本示例使用三个函数调用:用于初始化属性的调用、用于根据缺省属性设置所有变体
的调用,以及用于创建pthreads 的调用。

#include 
pthread_attr_t attr;
pthread_t tid;
void start_routine;
void arg;
int ret;

/* initialized with default attributes */
ret = pthread_attr_init (&tattr);
/* BOUND behavior */
ret = pthread_attr_setscope(&tattr, PTHREAD_SCOPE_SYSTEM);
ret = pthread_create (&tid, &tattr, start_routine, arg); 

pthread_attr_setscope 返回值
pthread_attr_setscope() 成功完成后将返回零。其他任何返回值都表示出现了错误。
如果出现以下情况,该函数将失败并返回对应的值。
EINVAL
描述: 尝试将tattr 设置为无效的值。

获取范围

请使用pthread_attr_getscope(3C)检索线程范围。
pthread_attr_getscope 语法

int pthread_attr_getscope(pthread_attr_t *tattr, int *scope);
#include 
pthread_attr_t tattr;
int scope;
int ret;

/* get scope of thread */
ret = pthread_attr_getscope(&tattr, &scope); 

pthread_attr_getscope 返回值
pthread_attr_getscope()成功完成后将返回零。其他任何返回值都表示出现了错误。
如果出现以下情况,该函数将失败并返回对应的值。
EINVAL
描述: scope 的值为NULL 或tattr 无效。

设置线程并行级别

针对标准符合性提供了pthread_setconcurrency(3C)。应用程序使用
pthread_setconcurrency()通知系统其所需的并发级别。对于Solaris 9 发行版中引入的
线程实现,此接口没有任何作用,所有可运行的线程都将被连接到LWP。

pthread_setconcurrency语法

#include 
int pthread_setconcurrency(int new_level);

pthread_setconcurrency 返回值
如果出现以下情况,pthread_setconcurrency()将失败:
EINVAL
描述: new_level 指定的值为负数。
EAGAIN
描述: new_level 指定的值将导致系统资源不足。

获取线程并行级别

pthread_getconcurrency(3C) 返回先前调用pthread_setconcurrency() 时设置的值。
pthread_getconcurrency 语法

#include 

int pthread_getconcurrency(void); 

如果以前未调用pthread_setconcurrency()函数,则pthread_getconcurrency() 将返回
零。
pthread_getconcurrency返回值
pthread_getconcurrency() 始终会返回先前调用pthread_setconcurrency() 时设置的并
发级别。如果从未调用pthread_setconcurrency(),则pthread_getconcurrency()将返
回零。

设置调度策略

请使用pthread_attr_setschedpolicy(3C) 设置调度策略。POSIX 标准指定SCHED_FIFO
(先入先出)、SCHED_RR(循环)或SCHED_OTHER(实现定义的方法)的调度策略属
性。
pthread_attr_setschedpolicy(3C) 语法

int pthread_attr_setschedpolicy(pthread_attr_t *tattr, int policy);
#include 
pthread_attr_t tattr;
int policy;
int ret; 

/* set the scheduling policy to SCHED_OTHER */
ret = pthread_attr_setschedpolicy(&tattr, SCHED_OTHER); 

SCHED_FIFO
如果调用进程具有有效的用户ID 0,则争用范围为系统(PTHREAD_SCOPE_SYSTEM) 的
先入先出线程属于实时(RT) 调度类。如果这些线程未被优先级更高的线程抢占,则
会继续处理该线程,直到该线程放弃或阻塞为止。对于具有进程争用范围
(PTHREAD_SCOPE_PROCESS) 的线程或其调用进程没有有效用户ID 0 的线程,请使用
SCHED_FIFOSCHED_FIFO基于TS 调度类。
SCHED_RR
如果调用进程具有有效的用户ID 0,则争用范围为系统(PTHREAD_SCOPE_SYSTEM) 的
循环线程属于实时(RT) 调度类。如果这些线程未被优先级更高的线程抢占,并且这
些线程没有放弃或阻塞,则在系统确定的时间段内将一直执行这些线程。对于具有
进程争用范围(PTHREAD_SCOPE_PROCES) 的线程,请使用SCHED_RR(基于TS 调度
类)。此外,这些线程的调用进程没有有效的用户ID 0。

SCHED_FIFOSCHED_RR 在POSIX 标准中是可选的,而且仅用于实时线程。

pthread_attr_setschedpolicy返回值
pthread_attr_setschedpolicy()成功完成后将返回零。其他任何返回值都表示出现了
错误。如果出现以下任一情况,该函数将失败并返回对应的值。
EINVAL
描述: 尝试将tattr 设置为无效的值。
ENOTSUP
描述: 尝试将该属性设置为不受支持的值。

获取调度策略

请使用pthread_attr_getschedpolicy(3C)检索调度策略。
pthread_attr_getschedpolicy语法

int pthread_attr_getschedpolicy(pthread_attr_t *tattr, int *policy);
#include 
pthread_attr_t tattr;
int policy;
int ret;
/* get scheduling policy of thread */
ret = pthread_attr_getschedpolicy (&tattr, &policy); 

pthread_attr_getschedpolicy返回值
pthread_attr_getschedpolicy() 成功完成后将返回零。其他任何返回值都表示出现了
错误。如果出现以下情况,该函数将失败并返回对应的值。
EINVAL
描述: 参数policy 为NULL 或tattr 无效。

设置继承的调度策略

请使用pthread_attr_setinheritsched(3C) 设置继承的调度策略。

pthread_attr_setinheritsched语法

int pthread_attr_setinheritsched(pthread_attr_t *tattr, int inherit);
#include 
pthread_attr_t tattr;
int inherit;
int ret;
/* use the current scheduling policy */
ret = pthread_attr_setinheritsched(&tattr, PTHREAD_EXPLICIT_SCHED); 

inherit 值PTHREAD_INHERIT_SCHED 表示新建的线程将继承创建者线程中定义的调度策
略。将忽略在pthread_create() 调用中定义的所有调度属性。如果使用缺省值
PTHREAD_EXPLICIT_SCHED,则将使用pthread_create() 调用中的属性。

pthread_attr_setinheritsched返回值
pthread_attr_setinheritsched()成功完成后将返回零。其他任何返回值都表示出现了
错误。如果出现以下任一情况,该函数将失败并返回对应的值。
EINVAL
描述: 尝试将tattr 设置为无效的值。
ENOTSUP
描述: 尝试将属性设置为不受支持的值。

获取继承的调度策略

pthread_attr_getinheritsched(3C)将返回由pthread_attr_setinheritsched()设置的
调度策略。

pthread_attr_getinheritsched语法

int pthread_attr_getinheritsched(pthread_attr_t *tattr, int *inherit);
#include 
pthread_attr_t tattr;
int inherit;
int ret; 

/* get scheduling policy and priority of the creating thread */
ret = pthread_attr_getinheritsched (&tattr, &inherit); 

pthread_attr_getinheritsched返回值
pthread_attr_getinheritsched()成功完成后将返回零。其他任何返回值都表示出现了
错误。如果出现以下情况,该函数将失败并返回对应的值。
EINVAL
描述: 参数inherit 为NULL 或tattr 无效。

设置调度参数

pthread_attr_setschedparam(3C) 可以设置调度参数。
pthread_attr_setschedparam 语法

int pthread_attr_setschedparam(pthread_attr_t *tattr,
            const struct sched_param *param);
#include 
pthread_attr_t tattr;
int newprio;
sched_param param;
newprio = 30; 

/* set the priority; others are unchanged */
param.sched_priority = newprio;
/* set the new scheduling param */
ret = pthread_attr_setschedparam (&tattr, ¶m); 

调度参数是在param 结构中定义的。仅支持优先级参数。新创建的线程使用此优先级运
行。
pthread_attr_setschedparam返回值
pthread_attr_setschedparam()成功完成后将返回零。其他任何返回值都表示出现了错
误。如果出现以下情况,该函数将失败并返回对应的值。
EINVAL
描述: param 的值为NULL 或tattr 无效。

可以采用两种方式之一来管理pthreads 优先级:
■ 创建子线程之前,可以设置优先级属性
■ 可以更改父线程的优先级,然后再将该优先级改回来

获取调度参数

pthread_attr_getschedparam(3C) 将返回由pthread_attr_setschedparam()定义的调度
参数。
pthread_attr_getschedparam语法

int pthread_attr_getschedparam(pthread_attr_t *tattr,
                const struct sched_param *param);
#include 
pthread_attr_t attr;
struct sched_param param;
int ret; 

/* get the existing scheduling param */
ret = pthread_attr_getschedparam (&tattr, ¶m); 

使用指定的优先级创建线程
创建线程之前,可以设置优先级属性。将使用在sched_param 结构中指定的新优先级创
建子线程。此结构还包含其他调度信息。

创建子线程时建议执行以下操作:
■ 获取现有参数
■ 更改优先级
■ 创建子线程
■ 恢复原始优先级
创建具有优先级的线程的示例
示例2 给出了使用不同于其父线程优先级的优先级创建子线程的示例。
示例2创建具有优先级的线程

#include 
#include 
pthread_attr_t tattr;
pthread_t tid;
int ret;
int newprio = 20;
sched_param param; 

/* initialized with default attributes */
ret = pthread_attr_init (&tattr);
/* safe to get existing scheduling param */
ret = pthread_attr_getschedparam (&tattr, ¶m);
/* set the priority; others are unchanged */
param.sched_priority = newprio;
/* setting the new scheduling param */
ret = pthread_attr_setschedparam (&tattr, ¶m);
/* with new priority specified */
ret = pthread_create (&tid, &tattr, func, arg); 

pthread_attr_getschedparam 返回值
pthread_attr_getschedparam()成功完成后将返回零。其他任何返回值都表示出现了错
误。如果出现以下情况,该函数将失败并返回对应的值。
EINVAL
描述: param 的值为NULL 或tattr 无效。

设置栈大小

pthread_attr_setstacksize(3C)可以设置线程栈大小。

pthread_attr_setstacksize 语法

int pthread_attr_setstacksize(pthread_attr_t *tattr,
                    size_t size);
#include 
pthread_attr_t tattr;
size_t size;
int ret; 
size = (PTHREAD_STACK_MIN + 0x4000); 

/* setting a new size */
ret = pthread_attr_setstacksize(&tattr, size); 

stacksize 属性定义系统分配的栈大小(以字节为单位)。size 不应小于系统定义的最小
栈大小
size 包含新线程使用的栈的字节数。如果size 为零,则使用缺省大小。在大多数情况
下,零值最适合。
PTHREAD_STACK_MIN 是启动线程所需的栈空间量。此栈空间没有考虑执行应用程序代码
所需的线程例程要求。

pthread_attr_setstacksize 返回值
pthread_attr_setstacksize() 成功完成后将返回零。其他任何返回值都表示出现了错
误。如果出现以下情况,该函数将失败并返回对应的值。
EINVAL
描述: size 值小于PTHREAD_STACK_MIN,或超出了系统强加的限制,或者tattr 无效。

获取栈大小

pthread_attr_getstacksize(3C)将返回由pthread_attr_setstacksize() 设置的栈大
小。
pthread_attr_getstacksize 语法

int pthread_attr_getstacksize(pthread_attr_t *tattr,
                    size_t *size);
#include 
pthread_attr_t tattr;
size_t size;
int ret; 

/* getting the stack size */
ret = pthread_attr_getstacksize(&tattr, &size); 

pthread_attr_getstacksize 返回值
pthread_attr_getstacksize()成功完成后将返回零。其他任何返回值都表示出现了错
误。如果出现以下情况,该函数将失败并返回对应的值。
EINVAL
描述: tattr 无效。

关于栈

通常,线程栈是从页边界开始的。任何指定的大小都被向上舍入到下一个页边界。不
具备访问权限的页将被附加到栈的溢出端。大多数栈溢出都会导致将SIGSEGV信号发送
到违例线程。将直接使用调用方分配的线程栈,而不进行修改。指定栈时,还应使用PTHREAD_CREATE_JOINABLE 创建线程。在该线程的pthread_join(3C)
调用返回之前,不会释放该栈。在该线程终止之前,不会释放该线程的栈。
了解这类线程是否已终止的唯一可靠方式是使用pthread_join(3C)

为线程分配栈空间

一般情况下,不需要为线程分配栈空间。系统会为每个线程的栈分配1MB(对于32 位
系统)或2MB(对于64 位系统)的虚拟内存,而不保留任何交换空间。系统将使用
mmap()MAP_NORESERVE选项来进行分配。

系统创建的每个线程栈都具有红色区域。系统通过将页附加到栈的溢出端来创建红色
区域,从而捕获栈溢出。此类页无效,而且会导致内存(访问时)故障。红色区域将
被附加到所有自动分配的栈,无论大小是由应用程序指定,还是使用缺省大小。
注– 对于库调用和动态链接,运行时栈要求有所变化。应绝对确定,指定的栈满足库调
用和动态链接的运行时要求。
极少数情况下需要指定栈和/或栈大小。甚至专家也很难了解是否指定了正确的大小。
甚至符合ABI 标准的程序也不能静态确定其栈大小。栈大小取决于执行中特定运行时
环境的需要。

生成自己的栈

指定线程栈大小时,必须考虑被调用函数以及每个要调用的后续函数的分配需求。需
要考虑的因素应包括调用序列需求、局部变量和信息结构。
有时,您需要与缺省栈略有不同的栈。典型的情况是,线程需要的栈大小大于缺省栈
大小。而不太典型的情况是,缺省大小太大。您可能正在使用不足的虚拟内存创建数
千个线程,进而处理数千个缺省线程栈所需的数千兆字节的栈空间。
对栈的最大大小的限制通常较为明显,但对其最小大小的限制如何呢?必须存在足够
的栈空间来处理推入栈的所有栈帧,及其局部变量等。
要获取对栈大小的绝对最小限制,请调用宏PTHREAD_STACK_MINPTHREAD_STACK_MIN
将针对执行NULL 过程的线程返回所需的栈空间量。有用的线程所需的栈大小大于最小
栈大小,因此缩小栈大小时应非常谨慎。

#include 
pthread_attr_t tattr;
pthread_t tid;
int ret;
size_t size = PTHREAD_STACK_MIN + 0x4000; 

/* initialized with default attributes */
ret = pthread_attr_init(&tattr);
/* setting the size of the stack also */
ret = pthread_attr_setstacksize(&tattr, size);
/* only size specified in tattr*/
ret = pthread_create(&tid, &tattr, start_routine, arg); 

设置栈地址和大小

pthread_attr_setstack(3C) 可以设置线程栈地址和大小。
pthread_attr_setstack(3C) 语法

int pthread_attr_setstack(pthread_attr_t *tattr,void *stackaddr,
                        size_t stacksize);
#include 
pthread_attr_t tattr;
void *base;
size_t size;
int ret; 

base = (void *) malloc(PTHREAD_STACK_MIN + 0x4000);
/* setting a new address and size */
ret = pthread_attr_setstack(&tattr, base,PTHREAD_STACK_MIN + 0x4000); 

stackaddr 属性定义线程栈的基准(低位地址)。stacksize 属性指定栈的大小。如果将
stackaddr 设置为非空值,而不是缺省的NULL,则系统将在该地址初始化栈,假设大小
为stacksize。
base 包含新线程使用的栈的地址。如果base 为NULL,则pthread_create(3C)将为大小
至少为stacksize 字节的新线程分配栈。

pthread_attr_setstack(3C)返回值
pthread_attr_setstack()成功完成后将返回零。其他任何返回值都表示出现了错误。
如果出现以下情况,该函数将失败并返回对应的值。
EINVAL
描述: base 或tattr 的值不正确。stacksize 的值小于PTHREAD_STACK_MIN
以下示例说明如何使用自定义栈地址和大小来创建线程。

#include 
pthread_attr_t tattr;
pthread_t tid;
int ret;
void *stackbase;
size_t size; 

/* initialized with default attributes */
ret = pthread_attr_init(&tattr);
/* setting the base address and size of the stack */
ret = pthread_attr_setstack(&tattr, stackbase,size);
/* address and size specified */
ret = pthread_create(&tid, &tattr, func, arg);

获取栈地址和大小

pthread_attr_getstack(3C) 将返回由pthread_attr_setstack()设置的线程栈地址和大
小。
pthread_attr_getstack语法

int pthread_attr_getstack(pthread_attr_t *tattr,void * *stackaddr,
                    size_t *stacksize);
#include 
pthread_attr_t tattr;
void *base;
size_t size;
int ret; 

/* getting a stack address and size */
ret = pthread_attr_getstackaddr (&tattr, &base, &size); 

pthread_attr_getstack 返回值
pthread_attr_getstackaddr()成功完成后将返回零。其他任何返回值都表示出现了错
误。如果出现以下情况,该函数将失败并返回对应的值。
EINVAL
描述: tattr 的值不正确。

你可能感兴趣的:(编程语言,多线程编程笔记)