Chinaunix首页 | 论坛 | 博客
  • 博客访问: 426816
  • 博文数量: 103
  • 博客积分: 5010
  • 博客等级: 大校
  • 技术积分: 971
  • 用 户 组: 普通用户
  • 注册时间: 2007-06-11 17:22
文章分类
文章存档

2008年(77)

2007年(26)

我的朋友

分类:

2008-05-01 02:52:40

1.等待线程终止
pthread_join() 函数会一直阻塞调用线程,直到指定的线程终止。

指定的线程必须位于当前的进程中,而且不得是分离线程。

如果多个线程等待同一个线程终止,则所有等待线程将一直等到目标线程终止。然后,一
个等待线程成功返回。其余的等待线程将失败并返回 ESRCH 错误。

在 pthread_join() 返回之后,应用程序可回收与已终止线程关联的任何数据存储空间。

ESRCH
   描述: 没有找到与给定的线程 ID 相对应的线程。
EDEADLK
   描述: 将出现死锁,如一个线程等待其本身,或者线程 A 和线程 B 互相等待。
EINVAL
   描述: 与给定的线程 ID 相对应的线程是分离线程。
pthread_join() 仅适用于非分离的目标线程。如果没有必要等待特定线程终止之后才进行
其他处理,则应当将该线程分离。

2.分离线程
int pthread_detach(thread_t tid);
可回收创建时 detachstate 属性设置为PTHREAD_CREATE_JOINABLE 的线程的存储空间。

pthread_detach() 函数用于指示应用程序在线程 tid 终止时回收其存储空间。如果 tid 尚未终
止,pthread_detach() 不会终止该线程。

3.为线程特定数据创建键
单线程 C 程序有两类基本数据:局部数据和全局数据。对于多线程 C 程序,添加了第三类
数据:线程特定数据。线程特定数据与全局数据非常相似,区别在于前者为线程专有。

线程特定数据基于每线程进行维护。TSD(特定于线程的数据)是定义和引用线程专用数
据的唯一方法。每个线程特定数据项都与一个作用于进程内所有线程的键关联。通过使用
key,线程可以访问基于每线程进行维护的指针 (void *)。

int    pthread_key_create(pthread_key_t *key, void (*destructor) (void *));
可以使用 pthread_key_create(3C) 分配用于标识进程中线程特定数据的键。键对进程中的
所有线程来说是全局的。创建线程特定数据时,所有线程最初都具有与该键关联的 NULL
值。

使用各个键之前,会针对其调用一次 pthread_key_create()。不存在对键(为进程中所有
的线程所共享)的隐含同步。

创建键之后,每个线程都会将一个值绑定到该键。这些值特定于线程并且针对每个线程单
独维护。如果创建该键时指定了 destructor 函数,则该线程终止时,系统会解除针对每线
程的绑定。

当 pthread_key_create() 成功返回时,会将已分配的键存储在 key 指向的位置中。调用方必
须确保对该键的存储和访问进行正确的同步。

使用可选的析构函数 destructor 可以释放过时的存储。如果某个键具有非 NULL destructor
函数,而线程具有一个与该键关联的非 NULL 值,则该线程退出时,系统将使用当前的相关
值调用 destructor 函数。destructor 函数的调用顺序不确定。

4.删除线程特定数据键
int pthread_key_delete(pthread_key_t key);
如果已删除键,则使用调用 pthread_setspecific() 或 pthread_getspecific() 引用该键
时,生成的结果将是不确定的。

程序员在调用删除函数之前必须释放所有线程特定资源。删除函数不会调用任何析构函
数。反复调用 pthread_key_create() 和 pthread_key_delete() 可能会产生问题。如果
pthread_key_delete() 将键标记为无效,而之后 key 的值不再被重用,那么反复调用它们就
会出现问题。对于每个所需的键,应当只调用 pthread_key_create() 一次。

5.设置线程特定数据
int pthread_setspecific(pthread_key_t key, const void *value);
为指定线程特定数据键设置线程特定绑定。
注 – 设置新绑定时,pthread_setspecific() 不会释放其存储空间。必须释放现有绑定,否
则会出现内存泄漏。

6.获取线程特定数据
使用 pthread_getspecific获取调用线程的键绑定,并将该绑定存储在 value 指向的
位置中。
void *pthread_getspecific(pthread_key_t key);

7.初始化线程
使用 pthread_once,可以在首次调用 pthread_once 时调用初始化例程。以后调用
pthread_once() 将不起作用。
pthread_once_t once_control = PTHREAD_ONCE_INIT;
int     pthread_once(pthread_once_t *once_control, void (*init_routine)(void));

8.停止执行线程
使用 sched_yield,可以使当前线程停止执行,以便执行另一个具有相同或更高优先级的线程。
int sched_yield(void);

9.设置线程的优先级
请使用 pthread_setschedparam 修改现有线程的优先级。此函数对于调度策略不起作用。
int     pthread_setschedparam(pthread_t tid, int policy, const struct sched_param *param);

10.获取线程的优先级
int     pthread_getschedparam(pthread_t tid, int policy, struct schedparam *param);

11.向线程发送信号
int pthread_kill(thread_t tid, int sig);

pthread_kill() 将信号 sig 发送到由 tid 指定的线程。tid 所指定的线程必须与调用线程在同
一个进程中。sig 参数必须来自 signal(5) 提供的列表。
如果 sig 为零,将执行错误检查,但并不实际发送信号。此错误检查可用来检查 tid 的有效
性。

12.访问调用线程的信号掩码
使用 pthread_sigmask更改或检查调用线程的信号掩码。
int pthread_sigmask(int how, const sigset_t *new, sigset_t *old);

SIG_BLOCK。向当前的信号掩码中添加 new,其中 new 表示要阻塞的信号组。
SIG_UNBLOCK。从当前的信号掩码中删除 new,其中 new 表示要取消阻塞的信号组。
SIG_SETMASK。将当前的信号掩码替换为 new,其中 new 表示新的信号掩码。

当 new 的值为 NULL 时,how 的值没有意义,线程的信号掩码不发生变化。要查询当前已阻
塞的信号,请将 NULL 值赋给 new 参数。

除非 old 变量为 NULL,否则 old 指向用来存储以前的信号掩码的空间。

13.安全地 Fork
int pthread_atfork(void (*prepare) (void), void (*parent) (void), void (*child)(void) );

pthread_atfork 返回值:
pthread_atfork() 在成功完成之后返回零。其他任何返回值都表示出现了错误。如果出现
以下情况,pthread_atfork() 将失败并返回相应的值。
ENOMEM
   描述: 表空间不足,无法记录 Fork 处理程序地址。

14.终止线程
void pthread_exit(void *status);

pthread_exit() 函数可用来终止调用线程。将释放所有线程特定数据绑定。如果调用线程
尚未分离,则线程 ID 和 status 指定的退出状态将保持不变,直到应用程序调用
pthread_join() 以等待该线程。否则,将忽略 status。

pthread_exit 返回值:
调用线程将终止,退出状态设置为 status 的内容。

15.线程的终止方式:(3种)
(1).从线程的第一个(最外面的)过程返回,即线程启动例程。请参见 pthread_create。
(2).调用 pthread_exit(),提供退出状态。
(3).使用 POSIX 取消函数执行终止操作。请参见 pthread_cancel()。

线程的缺省行为是拖延,直到其他线程通过 "joining" 拖延线程确认其已死亡。此行为与非
分离的缺省 pthread_create() 属性相同,join 的结果是 joining 线程得到已终止线程
的退出状态,已终止的线程将消失。

有一个重要的特殊情况,即当初始线程(即调用 main() 的线程)从 main() 调用返回时或调
用 exit() 时,整个进程及其所有的线程将终止。因此,一定要确保初始线程不会从 main()
过早地返回。

请注意,如果主线程仅仅调用了 pthread_exit,则仅主线程本身终止。进程及进程内的其
他线程将继续存在。所有线程都已终止时,进程也将终止。

16.取消线程
取消点
仅当取消操作安全时才应取消线程。pthreads 标准指定了几个取消点,其中包括:
  通过 pthread_testcancel 调用以编程方式建立线程取消点。
  线程等待 pthread_cond_wait 或 pthread_cond_timedwait(3C) 中的特定条件出现。
  被 sigwait(2) 阻塞的线程。
  一些标准的库调用。通常,这些调用包括线程可基于其阻塞的函数。有关列表,请参见
     cancellation(5)册页。

缺省情况下将启用取消功能。

放置取消点
执行取消操作存在一定的危险。大多数危险都与完全恢复不变量和释放共享资源有关。取
消线程时一定要格外小心,否则可能会使互斥保留为锁定状态,从而导致死锁。或者,已
取消的线程可能保留已分配的内存区域,但是系统无法识别这一部分内存,从而无法释放
它。
互斥肯定不是取消点
请将异步取消区域限制在没有外部依赖性的序列,因为外部依赖性可能会产生挂起的资源
或未解决的状态条件。在从某个备用的嵌套取消状态返回时,一定要小心地恢复取消状
态。该接口提供便于进行恢复的功能:pthread_setcancelstate(3C) 在所引用的变量中保留
当前的取消状态,pthread_setcanceltype(3C) 以同样的方式保留当前的取消类型。

无论何时,都应注意资源和状态恢已复到与起点一致的状态。

17.启用或禁用取消功能
请使用 pthread_setcancelstate启用或禁用线程取消功能。创建线程时,缺省情况下线
程取消功能处于启用状态。
int pthread_setcancelstate(int state, int *oldstate);

18.设置取消类型
使用 pthread_setcanceltype可以将取消类型设置为延迟或异步模式。
int pthread_setcanceltype(int type, int *oldtype);
创建线程时,缺省情况下会将取消类型设置为延迟模式。在延迟模式下,只能在取消点取
消线程。在异步模式下,可以在执行过程中的任意一点取消线程。因此建议不使用异步模
式。
PTHREAD_CANCEL_DEFERRED
PTHREAD_CANCEL_ASYNCHRONOUS

19.创建取消点
void pthread_testcancel(void);
当线程取消功能处于启用状态且取消类型设置为延迟模式时,pthread_testcancel() 函数
有效。如果在取消功能处于禁用状态下调用 pthread_testcancel(),则该函数不起作用。
请务必仅在线程取消操作安全的序列中插入 pthread_testcancel()。除通过
pthread_testcancel() 调用以编程方式建立的取消点以外,pthread 标准还指定了几个取消
点。

20.将处理程序推送到栈上
使用清理处理程序,可以将状态恢复到与起点一致的状态,其中包括清理已分配的资源和
恢复不变量。使用 pthread_cleanup_push 和 pthread_cleanup_pop 函数可以管理清
理处理程序。
在程序的同一词法域中可以推送和弹出清理处理程序。推送和弹出操作应当始终匹配,否
则会生成编译器错误。
使用 pthread_cleanup_push 将清理处理程序推送到清理栈 (LIFO)。
void pthread_cleanup_push(void(*routine)(void *), void *args);

21.从栈中弹出处理程序
使用 pthread_cleanup_pop 从清理栈中弹出清理处理程序。
void pthread_cleanup_pop(int execute);

如果弹出函数中的参数为非零值,则会从栈中删除该处理程序并执行该处理程序。如果该
参数为零,则会弹出该处理程序,而不执行它。
线程显式或隐式调用 pthread_exit 时,或线程接受取消请求时,会使用非零参数有效地
调用 pthread_cleanup_pop()。












阅读(1058) | 评论(0) | 转发(0) |
0

上一篇:chap1 多线程基础介绍

下一篇:线程取消

给主人留下些什么吧!~~