多线程编程指南

相似的 Solaris 线程函数

表 8–3 相似的 Solaris 线程函数

操作 

相关函数说明 

创建线程 

thr_create 语法

获取最小的栈大小 

thr_min_stack 语法

获取线程标识符 

thr_self 语法

停止执行线程 

thr_yield 语法

向线程发送信号 

thr_kill 语法

访问调用线程的信号掩码 

thr_sigsetmask 语法

终止线程 

thr_exit 语法

等待线程终止 

thr_join 语法

创建线程特定的数据键 

thr_keycreate 语法

设置线程特定数据 

thr_setspecific 语法

获取线程特定数据 

thr_getspecific 语法

设置线程优先级 

thr_setprio 语法

获取线程优先级 

thr_getprio 语法

创建线程

thr_create(3C) 例程是 Solaris 线程接口中最详细的所有例程其中之一。

使用 thr_create(3C) 可以向当前的进程中增加新的受控线程。对于 POSIX 线程,请参见pthread_create 语法

thr_create 语法

#include <thread.h>



int thr_create(void *stack_base, size_t stack_size,

    void *(*start_routine) (void *), void *arg, long flags,

    thread_t *new_thread);



size_t thr_min_stack(void);

请注意,新线程不会继承暂挂的信号,但确实会继承优先级和信号掩码。

stack_base。包含新线程所使用的栈的地址。如果 stack_baseNULL,则 thr_create() 会为新线程分配一个至少为 stack_size 字节的栈。

stack_size。包含新线程所使用的栈的大小(以字节数表示)。如果 stack_size 为零,则使用缺省大小。在大多数情况下,零值最适合。如果 stack_size 不为零,则 stack_size 必须大于 thr_min_stack() 返回的值。

通常,无需为线程分配栈空间。系统会为每个线程的没有保留交换空间的栈分配 1 MB 的虚拟内存。系统使用 mmap(2)-MAP_NORESERVE 选项来进行分配。

start_routine。包含用以开始执行新线程的函数。start_routine() 返回时,该线程将退出,并且其退出状态会设置为 start_routine 返回的值。请参见thr_exit 语法

arg。可以是 void 所描述的任何变量,通常是任何大小为 4 字节的值。对于较大的值,必须通过将该参数指向对应的变量来间接传递。

请注意,仅可以提供一个参数。要在程序中采用多个参数,请将多个参数编码为单个参数,如通过将这些参数放在一个结构中。

flags。指定所创建的线程的属性。在大多数情况下,最适合使用零值。

flags 中的值是通过对以下参数执行按位或运算(包含边界值)来构造的:


注 –

如果没有明确分配同步,则未暂停的分离线程会失败。如果失败,则从 thr_create() 返回该线程的创建者之前,会将该线程 ID 重新指定给另一个新线程。


new_thread。如果 new_thread 不为 NULL,则它将指向 thr_create() 成功时用来存储新线程 ID 的位置。调用方负责提供该参数所指向的存储空间。线程 ID 仅在调用进程中有效。

如果对该标识符不感兴趣,请向 new_thread 提供一个 NULL 值。

thr_create 返回值

thr_create() 函数在成功完成之后返回零。其他任何返回值都表示出现了错误。如果检测到以下情况之一,thr_create() 将失败并返回对应的值。


EAGAIN

描述:

超出了系统限制,如创建的 LWP 过多。


ENOMEM

描述:

可用内存不足,无法创建新线程。


EINVAL

描述:

stack_base 不为 NULL,并且 stack_size 小于 thr_min_stack() 返回的值。

获取最小栈大小

使用 thr_min_stack(3C) 可以获取线程的最小栈大小。

Solaris 线程中的栈行为通常与 pthread 中的栈行为相同。有关设置和操作栈的更多信息,请参见关于栈

thr_min_stack 语法

#include <thread.h>



size_t thr_min_stack(void);

thr_min_stack() 会返回执行空线程所需的空间量。创建空线程的目的是执行空过程。由于有用线程需要的栈要大于绝对最小栈,因此在减小栈大小时请务必小心。

执行非空过程的线程所分配的栈大小应大于 thr_min_stack() 的大小。

如果某个线程是借助于用户提供的栈创建的,则用户必须保留足够的空间才能运行该线程。动态链接的执行环境会增加确定线程最小栈要求的难度。

可以通过两种方法来指定自定义栈。第一种方法是为栈位置提供 NULL,从而要求运行时库为该栈分配空间,但是向 thr_create() 提供 stacksize 参数中所需的大小。

另一种方法是全面负责栈管理的各个方面,并向 thr_create() 提供一个指向该栈的指针。这意味着不但需要负责分配栈,还需要负责取消分配栈。线程终止时,必须安排对该线程的栈进行处理。

当您分配自己的栈时,请确保通过调用 mprotect(2) 在该栈末尾附加一个红色区域。

大多数用户都不应当通过用户提供的栈来创建线程。用户提供的栈之所以存在,只是为了支持要求对其执行环境进行完全控制的应用程序。

相反,用户应当由系统来管理对栈的分配。系统提供的缺省栈应当能够满足所创建的任何线程的要求。

thr_min_stack 返回值

未定义任何错误。

获取线程标识符

使用 thr_self(3C) 可以获取调用线程的 ID。对于 POSIX 线程,请参见pthread_self 语法

thr_self 语法

#include <thread.h>



thread_t thr_self(void);

thr_self 返回值

未定义任何错误。

停止执行线程

thr_yield(3C) 会导致当前的线程停止执行,以便执行另一个具有相同或更高优先级的线程。 否则,thr_yield() 不起任何作用。但是,调用 thr_yield() 无法保证当前的线程会停止执行。

thr_yield 语法

#include <thread.h>



void thr_yield(void);

thr_yield 返回值

thr_yield() 不会返回任何内容并且不会设置 errno

向线程发送信号

thr_kill(3C) 可用来向线程发送信号。对于 POSIX 线程,请参见pthread_self 语法

thr_kill 语法

#include <thread.h>

#include <signal.h>

int thr_kill(thread_t target_thread, int sig);

thr_kill 返回值

如果成功完成,thr_kill() 将返回 0。如果检测到以下任一情况,thr_kill() 将失败并返回对应的值。如果失败,则不发送任何信号。


ESRCH

描述:

未找到与 thread ID 所指定的线程相关联的线程。


EINVAL

描述:

sig 参数值不为零。sig 无效或者是不支持的信号编号。

访问调用线程的信号掩码

使用 thr_sigsetmask(3C) 可以更改或检查调用线程的信号掩码。

thr_sigsetmask 语法

#include <thread.h>

#include <signal.h>

int thr_sigsetmask(int how, const sigset_t *set, sigset_t *oset);

thr_sigsetmask() 可用来更改或检查调用线程的信号掩码。每个线程都有自已的信号掩码。新线程会继承调用线程的信号掩码和优先级,但不会继承暂挂的信号。新线程的暂挂信号将为空。

如果参数 set 的值不为 NULL,则 set 会指向一组信号,这组信号可用来修改当前阻塞的信号组。如果 set 的值为 NULL,则 how 的值没有意义,并且不会修改线程的信号掩码。使用此行为可了解有关当前阻塞的信号的情况。

how 的值可指定更改信号组的方法。how 可以为以下值之一。

thr_sigsetmask 返回值

如果成功完成,thr_sigsetmask() 将返回 0。如果检测到以下任一情况,thr_sigsetmask() 将失败并返回对应的值。


EINVAL

描述:

set 不为 NULL,并且 how 的值未定义。

终止线程

使用 thr_exit(3C) 可以终止线程。对于 POSIX 线程,请参见pthread_exit 语法

thr_exit 语法

#include <thread.h>



void thr_exit(void *status);

thr_exit 返回值

thr_exit() 不返回到其调用方。

等待线程终止

使用 thr_join(3C) 可以等待目标线程终止。对于 POSIX 线程,请参见pthread_join 语法

thr_join 语法

#include <thread.h>



int thr_join(thread_t tid, thread_t *departedid, void **status);

目标线程必须是当前进程的成员,而不能是分离线程或守护进程线程。

多个线程不能等待同一个线程完成,否则仅有一个线程会成功完成。其他线程将终止,并返回 ESRCH 错误。

如果目标线程已经终止,thr_join() 将不会阻塞对调用线程的处理。

thr_join,加入特定线程

#include <thread.h>



thread_t tid;

thread_t departedid;

int ret;

void *status;



/* waiting to join thread "tid" with status */

ret = thr_join(tid, &departedid, &status);



/* waiting to join thread "tid" without status */

ret = thr_join(tid, &departedid, NULL);



/* waiting to join thread "tid" without return id and status */

ret = thr_join(tid, NULL, NULL); 

如果 tid(thread_t)0,则 thread_join() 将等待进程中的任何非分离线程终止。换句话说,如果未指定线程标识符,则任何未分离的线程退出都将导致返回 thread_join()

thr_join,加入任何线程

#include <thread.h>



thread_t tid;

thread_t departedid;

int ret;

void *status;



/* waiting to join any non-detached thread with status */

ret = thr_join(0, &departedid, &status); 

通过在 Solaris thr_join() 中使用 0 来表示线程 ID,进程中的任何非分离线程退出时都将执行加入操作。departedid 表示现有线程的线程 ID。

thr_join 返回值

thr_join() 在成功运行后返回 0。如果检测到以下任一情况,thr_join() 将失败并返回对应的值。


ESRCH

描述:

未找到与目标线程 ID 对应的非分离线程。


EDEADLK

描述:

检测到死锁,或者目标线程的值指定了调用线程。

创建线程特定的数据键

使用 thr_keycreate(3C) 可分配键,用于标识进程中线程特定数据。键可全局应用于进程中的所有线程。创建键时,每个线程都会将一个值与其绑定。

除了函数的名称和参数以外,Solaris 线程的线程特定数据与 POSIX 线程的线程特定数据完全相同。本节概述了 Solaris 函数。 对于 POSIX 线程,请参见pthread_key_create 语法

thr_keycreate 语法

#include <thread.h>



int thr_keycreate(thread_key_t *keyp,

    void (*destructor) (void *value));

keyp 为每个绑定线程单独维护特定的值。所有的线程最初都会绑定到专用元素 keyp,该元素可用于访问其线程特定数据。创建键时,对于所有活动线程,将为新键赋予值 NULL。此外在创建线程时,还会为以前在新线程中创建的所有键赋予值 NULL。

destructor 函数是可选的,可以将其与每个 keyp 相关联。线程退出时,如果 keyp 具有非 NULL 的 destructor,并且线程具有与 keyp 相关联的非 NULL value,则 destructor 将用当前的关联 value 进行调用。如果线程退出时存在多个 destructor 与其相关,则 destructor 的调用顺序是不确定的。

thr_keycreate 返回值

thr_keycreate() 在成功运行后返回 0。如果检测到以下任一情况,thr_keycreate() 将失败并返回对应的值。


EAGAIN

描述:

系统资源不足,无法创建另一个线程特定的数据键,或者键数目超过了 PTHREAD_KEYS_MAX 的每进程限制。


ENOMEM

描述:

可用内存不足,无法将 valuekeyp 相关联。

设置线程特定的数据值

thr_setspecific(3C) 可用来将 value 绑定到线程特定的数据键(对于调用线程来说为 key)。对于 POSIX 线程,请参见pthread_setspecific 语法

thr_setspecific 语法

#include <thread.h>



int thr_setspecific(thread_key_t key, void *value);

thr_setspecific 返回值

thr_setspecific() 在成功运行后返回 0。如果检测到以下任一情况,thr_setspecific() 将失败并返回对应的值。


ENOMEM

描述:

可用内存不足,无法将 valuekeyp 相关联。


EINVAL

描述:

keyp 无效。

获取线程特定的数据值

thr_getspecific(3C) 可用来将当前绑定到调用线程的 key 的值存储到 valuep 所指向的位置。对于 POSIX 线程,请参见pthread_getspecific 语法

thr_getspecific 语法

#include <thread.h>



int thr_getspecific(thread_key_t key, void **valuep);

thr_getspecific 返回值

thr_getspecific() 在成功运行后返回 0。如果检测到以下任一情况,thr_getspecific() 将失败并返回对应的值。


ENOMEM

描述:

可用内存不足,无法将 valuekeyp 相关联。


EINVAL

描述:

keyp 无效。

设置线程的优先级

在 Solaris 线程中,对于在创建时与父线程具有不同优先级的线程,可以在 SUSPEND 模式下创建。在暂停之后,可以通过使用 thr_setprio(3C) 函数调用来修改线程的优先级。thr_setprio() 完成之后,线程可恢复执行。

争用同步对象时,高优先级的线程优先于低优先级的线程。

thr_setprio 语法

thr_setprio(3C) 可用来将当前进程内 tid 所指定线程的优先级更改为 newprio 所指定的优先级。对于 POSIX 线程,请参见pthread_setschedparam 语法

#include <thread.h>



int thr_setprio(thread_t tid, int newprio)

缺省情况下,线程是基于范围从 0(最不重要)到 127(最重要)的固定优先级来调度的。

thread_t tid;

int ret;

int newprio = 20;



/* suspended thread creation */

ret = thr_create(NULL, NULL, func, arg, THR_SUSPENDED, &tid);



/* set the new priority of suspended child thread */

ret = thr_setprio(tid, newprio);



/* suspended child thread starts executing with new priority */

ret = thr_continue(tid);

thr_setprio 返回值

thr_setprio() 在成功运行后返回 0。如果检测到以下任一情况,thr_setprio() 将失败并返回对应的值。


ESRCH

描述:

tid 指定的值不引用现有的线程。


EINVAL

描述:

priority 的值对于与 tid 相关联的调度类没有意义。

获取线程的优先级

使用 thr_getprio(3C) 可以获取线程的当前优先级。每个线程都从其创建者继承优先级。thr_getprio() 会将当前的优先级 tid 存储到 newprio 所指向的位置。对于 POSIX 线程,请参见pthread_getschedparam 语法

thr_getprio 语法

#include <thread.h>



int thr_getprio(thread_t tid, int *newprio)

thr_getprio 返回值

thr_getprio() 在成功运行后返回 0。如果检测到以下情况,thr_getprio() 将失败并返回对应的值。


ESRCH

描述:

tid 指定的值不会引用现有的线程。