操作 |
相关函数说明 |
---|---|
创建线程 | |
获取最小的栈大小 | |
获取线程标识符 | |
停止执行线程 | |
向线程发送信号 | |
访问调用线程的信号掩码 | |
终止线程 | |
等待线程终止 | |
创建线程特定的数据键 | |
设置线程特定数据 | |
获取线程特定数据 | |
设置线程优先级 | |
获取线程优先级 |
thr_create(3C) 例程是 Solaris 线程接口中最详细的所有例程其中之一。
使用 thr_create(3C) 可以向当前的进程中增加新的受控线程。对于 POSIX 线程,请参见pthread_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_base 为 NULL,则 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_SUSPENDED。暂停新线程,并且不执行 start_routine,直到 thr_continue() 启动该线程为止。使用 THR_SUSPENDED 可以在运行该线程之前对其执行操作,如更改其优先级。
THR_DETACHED。分离新线程,以便在该线程终止之后,可以立即重用其线程 ID 和其他资源。如果不想等待线程终止,可以设置 THR_DETACHED。
如果没有明确分配同步,则未暂停的分离线程会失败。如果失败,则从 thr_create() 返回该线程的创建者之前,会将该线程 ID 重新指定给另一个新线程。
THR_BOUND。将新线程永久绑定到 LWP。新线程是绑定线程。从 Solaris 9 发行版开始,系统不再区分绑定线程和非绑定线程,所有的线程均视为绑定线程。
THR_DAEMON。将新线程标记为守护进程。守护进程线程始终处于分离状态。THR_DAEMON 表示 THR_DETACHED。所有非守护进程线程退出时,该进程也会随之退出。守护进程线程不会影响进程的退出状态,并且在退出对线程数进行计数时会被忽略。
进程的退出方法有两种,一是调用 exit(),二是使用进程中不是通过 THR_DAEMON 标志创建的每个线程来调用 thr_exit(3C)。 进程所调用的应用程序或库可以创建一个或多个线程,在确定是否退出时应当忽略(不计数)这些线程。THR_DAEMON 标志可标识在进程退出条件中不计数的线程。
new_thread。如果 new_thread 不为 NULL,则它将指向 thr_create() 成功时用来存储新线程 ID 的位置。调用方负责提供该参数所指向的存储空间。线程 ID 仅在调用进程中有效。
如果对该标识符不感兴趣,请向 new_thread 提供一个 NULL 值。
thr_create() 函数在成功完成之后返回零。其他任何返回值都表示出现了错误。如果检测到以下情况之一,thr_create() 将失败并返回对应的值。
EAGAIN
描述:超出了系统限制,如创建的 LWP 过多。
ENOMEM
描述:可用内存不足,无法创建新线程。
使用 thr_min_stack(3C) 可以获取线程的最小栈大小。
Solaris 线程中的栈行为通常与 pthread 中的栈行为相同。有关设置和操作栈的更多信息,请参见关于栈。
#include <thread.h> size_t thr_min_stack(void);
thr_min_stack() 会返回执行空线程所需的空间量。创建空线程的目的是执行空过程。由于有用线程需要的栈要大于绝对最小栈,因此在减小栈大小时请务必小心。
执行非空过程的线程所分配的栈大小应大于 thr_min_stack() 的大小。
如果某个线程是借助于用户提供的栈创建的,则用户必须保留足够的空间才能运行该线程。动态链接的执行环境会增加确定线程最小栈要求的难度。
可以通过两种方法来指定自定义栈。第一种方法是为栈位置提供 NULL,从而要求运行时库为该栈分配空间,但是向 thr_create() 提供 stacksize 参数中所需的大小。
另一种方法是全面负责栈管理的各个方面,并向 thr_create() 提供一个指向该栈的指针。这意味着不但需要负责分配栈,还需要负责取消分配栈。线程终止时,必须安排对该线程的栈进行处理。
当您分配自己的栈时,请确保通过调用 mprotect(2) 在该栈末尾附加一个红色区域。
大多数用户都不应当通过用户提供的栈来创建线程。用户提供的栈之所以存在,只是为了支持要求对其执行环境进行完全控制的应用程序。
相反,用户应当由系统来管理对栈的分配。系统提供的缺省栈应当能够满足所创建的任何线程的要求。
未定义任何错误。
使用 thr_self(3C) 可以获取调用线程的 ID。对于 POSIX 线程,请参见pthread_self 语法。
#include <thread.h> thread_t thr_self(void);
未定义任何错误。
thr_yield(3C) 会导致当前的线程停止执行,以便执行另一个具有相同或更高优先级的线程。 否则,thr_yield() 不起任何作用。但是,调用 thr_yield() 无法保证当前的线程会停止执行。
#include <thread.h> void thr_yield(void);
thr_yield() 不会返回任何内容并且不会设置 errno。
thr_kill(3C) 可用来向线程发送信号。对于 POSIX 线程,请参见pthread_self 语法。
#include <thread.h> #include <signal.h> int thr_kill(thread_t target_thread, int sig);
如果成功完成,thr_kill() 将返回 0。如果检测到以下任一情况,thr_kill() 将失败并返回对应的值。如果失败,则不发送任何信号。
ESRCH
描述:未找到与 thread ID 所指定的线程相关联的线程。
EINVAL
描述:sig 参数值不为零。sig 无效或者是不支持的信号编号。
使用 thr_sigsetmask(3C) 可以更改或检查调用线程的信号掩码。
#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 可以为以下值之一。
SIG_BLOCK。set 对应于一组要阻塞的信号。这些信号会添加到当前的信号掩码中。
SIG_UNBLOCK。set 对应于一组要解除阻塞的信号。这些信号会从当前的信号掩码中删除。
SIG_SETMASK。set 对应于新的信号掩码。当前的信号掩码将替换为 set。
如果成功完成,thr_sigsetmask() 将返回 0。如果检测到以下任一情况,thr_sigsetmask() 将失败并返回对应的值。
EINVAL
描述:set 不为 NULL,并且 how 的值未定义。
使用 thr_exit(3C) 可以终止线程。对于 POSIX 线程,请参见pthread_exit 语法。
#include <thread.h> void thr_exit(void *status);
使用 thr_join(3C) 可以等待目标线程终止。对于 POSIX 线程,请参见pthread_join 语法。
#include <thread.h> int thr_join(thread_t tid, thread_t *departedid, void **status);
目标线程必须是当前进程的成员,而不能是分离线程或守护进程线程。
多个线程不能等待同一个线程完成,否则仅有一个线程会成功完成。其他线程将终止,并返回 ESRCH 错误。
如果目标线程已经终止,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()。
#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() 在成功运行后返回 0。如果检测到以下任一情况,thr_join() 将失败并返回对应的值。
ESRCH
描述:未找到与目标线程 ID 对应的非分离线程。
EDEADLK
描述:检测到死锁,或者目标线程的值指定了调用线程。
使用 thr_keycreate(3C) 可分配键,用于标识进程中线程特定数据。键可全局应用于进程中的所有线程。创建键时,每个线程都会将一个值与其绑定。
除了函数的名称和参数以外,Solaris 线程的线程特定数据与 POSIX 线程的线程特定数据完全相同。本节概述了 Solaris 函数。 对于 POSIX 线程,请参见pthread_key_create 语法。
#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() 在成功运行后返回 0。如果检测到以下任一情况,thr_keycreate() 将失败并返回对应的值。
EAGAIN
描述:系统资源不足,无法创建另一个线程特定的数据键,或者键数目超过了 PTHREAD_KEYS_MAX 的每进程限制。
ENOMEM
描述:可用内存不足,无法将 value 与 keyp 相关联。
thr_setspecific(3C) 可用来将 value 绑定到线程特定的数据键(对于调用线程来说为 key)。对于 POSIX 线程,请参见pthread_setspecific 语法。
#include <thread.h> int thr_setspecific(thread_key_t key, void *value);
thr_setspecific() 在成功运行后返回 0。如果检测到以下任一情况,thr_setspecific() 将失败并返回对应的值。
ENOMEM
描述:可用内存不足,无法将 value 与 keyp 相关联。
EINVAL
描述:keyp 无效。
thr_getspecific(3C) 可用来将当前绑定到调用线程的 key 的值存储到 valuep 所指向的位置。对于 POSIX 线程,请参见pthread_getspecific 语法。
#include <thread.h> int thr_getspecific(thread_key_t key, void **valuep);
thr_getspecific() 在成功运行后返回 0。如果检测到以下任一情况,thr_getspecific() 将失败并返回对应的值。
ENOMEM
描述:可用内存不足,无法将 value 与 keyp 相关联。
EINVAL
描述:keyp 无效。
在 Solaris 线程中,对于在创建时与父线程具有不同优先级的线程,可以在 SUSPEND 模式下创建。在暂停之后,可以通过使用 thr_setprio(3C) 函数调用来修改线程的优先级。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() 在成功运行后返回 0。如果检测到以下任一情况,thr_setprio() 将失败并返回对应的值。
ESRCH
描述:tid 指定的值不引用现有的线程。
EINVAL
描述:priority 的值对于与 tid 相关联的调度类没有意义。
使用 thr_getprio(3C) 可以获取线程的当前优先级。每个线程都从其创建者继承优先级。thr_getprio() 会将当前的优先级 tid 存储到 newprio 所指向的位置。对于 POSIX 线程,请参见pthread_getschedparam 语法。
#include <thread.h> int thr_getprio(thread_t tid, int *newprio)
thr_getprio() 在成功运行后返回 0。如果检测到以下情况,thr_getprio() 将失败并返回对应的值。
ESRCH
描述:tid 指定的值不会引用现有的线程。