Linux基本线程编程(三)

删除线程特定数据键
使用pthread_key_delete(3C)可以销毁现有线程特定数据键。由于键已经无效,因此将释放与该键关联的所有内存。引用无效键将返回错误。Solaris线程中没有类似的函数。
*pthread_key_delete语法*
int pthread_key_delete(pthread_key_t key);

#include <pthread.h>
pthread_key_t key;
int ret;
/* key previously created */
ret = pthread_key_delete(key);

如果已删除键,则使用调用pthread_setspecific()或pthread_getspecific()引用该键时,生成的结果将是不确定的。在调用删除函数之前必须释放所有线程特定资源。删除函数不会调用任何析构函数。反复调用pthread_key_create()和pthread_key_delete()可能会产生问题。如果pthread_key_delete()将键标记为无效,而之后key的值不再被重用,那么反复调用它们就会出现问题。对于每个所需的键,应当只调用pthread_key_create()一次。
pthread_key_delete返回值
pthread_key_delete()在成功完成之后返回零。其他任何返回值都表示出现了错误。如果出现以下情况,pthread_key_delete()将失败并返回相应的值。
EINVAL
描述: key的值无效。
设置线程特定数据
使用pthread_setspecific(3C)可以为指定线程特定数据键设置线程特定绑定。
pthread_setspecific语法
int pthread_setspecific(pthread_key_t key, const void *value);

#include <pthread.h>
pthread_key_t key;
void *value;
int ret;
/* key previously created */
ret = pthread_setspecific(key, value);

pthread_setspecific返回值
pthread_setspecific()在成功完成之后返回零。其他任何返回值都表示出现了错误。如果出现以下任一情况,pthread_setspecific()将失败并返回相应的值。
ENOMEM
描述: 虚拟内存不足。
EINVAL
描述: key无效。
注– 设置新绑定时,pthread_setspecific()不会释放其存储空间。必须释放现有绑定,否则会出现内存泄漏。
获取线程特定数据
请使用pthread_getspecific(3C)获取调用线程的键绑定,并将该绑定存储在value指向的位置中。
pthread_getspecific语法
void *pthread_getspecific(pthread_key_t key);

#include <pthread.h>
pthread_key_t key;
void *value;
/* key previously created */
value = pthread_getspecific(key);

pthread_getspecific返回值
pthread_getspecific不返回任何错误。
全局和专用线程特定数据的示例
示例3-1的代码是从多线程程序中摘录出来的。这段代码可以由任意数量的线程执行,但该代码引用了两个全局变量:errno和mywindow。这些全局值实际上应当是对每个线程专用项的引用。
示例3-1 线程特定数据-全局但专用


body() {
...
while (write(fd, buffer, size) == -1) {
if (errno != EINTR) {
fprintf(mywindow, "%s\n", strerror(errno));
exit(1);
}
}
...
}

errno引用应该从线程所调用的例程获取系统错误,而从其他线程所调用的例程获取系统错误。因此,线程不同,引用errno所指向的存储位置也不同。
mywindow变量指向一个stdio(标准IO)流,作为线程专属的流窗口。因此,与errno一样,线程不同,引用mywindow所指向的存储位置也不同。最终,这个引用指向不同的流窗口。唯一的区别在于系统负责处理errno,而程序员必须处理对mywindow的引用。
下一个示例说明对mywindow的引用如何工作。预处理程序会将对mywindow的引用转换为对_mywindow()过程的调用。
此例程随后调用pthread_getspecific()。pthread_getspecific()接收mywindow_key全局变量作为输入参数,以输出参数win返回该线程的窗口。
示例3–2 将全局引用转化为专用引用
thread_key_t mywin_key;

FILE *_mywindow(void) {
FILE *win;
win = pthread_getspecific(mywin_key);
return(win)“`

```
#define mywindow _mywindow()
void routine_uses_win( FILE *win) {
...
}
...
make_mywin();
...
routine_uses_win( mywindow )
...
}

mywin_key变量标识一类变量,对于该类变量,每个线程都有其各自的专用副本。这些变量是线程特定数据。每个线程都调用make_mywin()以初始化其时限并安排其mywindow实例以引用线程特定数据。
调用此例程之后,此线程可以安全地引用mywindow,调_mywindow()之后,此线程将获得对其专用时限的引用。引用mywindow类似于直接引用线程专用数据。
示例3-3说明如何设置引用。

示例3-3 初始化线程特定数据

void make_mywindow(void) {
FILE **win;
static pthread_once_t mykeycreated = PTHREAD_ONCE_INIT;
pthread_once(&mykeycreated, mykeycreate);
win = malloc(sizeof(*win));
create_window(win, ...);
pthread_setspecific(mywindow_key, win);
}
void mykeycreate(void) {
pthread_key_create(&mywindow_key, free_key);
}
void free_key(void *win) {
free(win);
}

首先,得到一个唯一的键值,mywin_key。此键用于标识线程特定数据类。第一个调用make_mywin()的线程最终会调用pthread_key_create(),该函数将唯一的key赋给其第一个参数。第二个参数是destructor函数,用于在线程终止后将该线程的特定于该线程的数据项实例解除分配。接下来为调用方的线程特定数据项的实例分配存储空间。获取已分配的存储空间,调用create_window(),以便为该线程设置时限。win指向为该时限分配的存储空间。最后,调用pthread_setspecific(),将win与该键关联。以后,每当线程调用pthread_getspecific()以传递全局key,线程都会获得它在前一次调
用pthread_setspecific()时设置的与该键关联的值)。线程终止时,会调用在pthread_key_create()中设置的destructor函数。每个destructor
函数仅在终止线程通过调用pthread_setspecific()为key赋值之后才会被调用。
获取线程标识符
请使用 pthread_self(3C) 获取调用线程的 thread identifier。
pthread_self语法
pthread_t pthread_self(void);

#include <pthread.h>

pthread_t tid;

tid = pthread_self();

pthread_self返回值
pthread_self() 返回调用线程的 thread identifier。

比较线程ID

请使用pthread_equal(3C)对两个线程的线程标识号进行比较。
pthread_equal语法
int pthread_equal(pthread_t tid1, pthread_t tid2);

#include <pthread.h>

pthread_t tid1, tid2;
int ret;

ret = pthread_equal(tid1, tid2);

pthread_equal返回值
如果tid1和tid2相等,pthread_equal()将返回非零值,否则将返回零。如果tid1或tid2是无效的线程标识号,则结果无法预测。
初始化线程
使用pthread_once(3C),可以在首次调用pthread_once时调用初始化例程。以后调用pthread_once()将不起作用。

pthread_once语法
int pthread_once(pthread_once_t *once_control,
void (*init_routine)(void));

#include <pthread.h>

pthread_once_t once_control = PTHREAD_ONCE_INIT;
int ret;

ret = pthread_once(&once_control, init_routine);

once_control参数用来确定是否已调用相关的初始化例程。

pthread_once返回值
pthread_once()在成功完成之后返回零。其他任何返回值都表示出现了错误。如果出现以下情况,pthread_once()将失败并返回相应的值。
EINVAL
描述: once_control或init_routine是NULL。
停止执行线程
使用sched_yield(3RT),可以使当前线程停止执行,以便执行另一个具有相同或更高优先级的线程。

sched_yield语法
int sched_yield(void);

#include <sched.h>

int ret;

ret = sched_yield();

sched_yield返回值
sched_yield()在成功完成之后返回零。否则,返回-1,并设置errno以指示错误状态。
ENOSYS
描述: 本实现不支持sched_yield。
设置线程的优先级
请使用pthread_setschedparam(3C)修改现有线程的优先级。此函数对于调度策略不起作用。
pthread_setschedparam语法
int pthread_setschedparam(pthread_t tid, int policy,
const struct sched_param *param);

#include <pthread.h>
pthread_t tid;
int ret;
struct sched_param param;
int priority;
/* sched_priority will be the priority of the thread */
sched_param.sched_priority = priority;
policy = SCHED_OTHER;
/* scheduling parameters of target thread */
ret = pthread_setschedparam(tid, policy, &param);

pthread_setschedparam返回值
pthread_setschedparam()在成功完成之后返回零。其他任何返回值都表示出现了错误。如果出现以下任一情况,pthread_setschedparam()函数将失败并返回相应的值。
EINVAL
描述: 所设置属性的值无效。
ENOTSUP
描述: 尝试将该属性设置为不受支持的值。
获取线程的优先级
pthread_getschedparam(3C)可用来获取现有线程的优先级。
pthread_getschedparam语法
int pthread_getschedparam(pthread_t tid, int policy,
struct schedparam *param);

#include <pthread.h>
pthread_t tid;
sched_param param;
int priority;
int policy;
int ret;
/* scheduling parameters of target thread */
ret = pthread_getschedparam (tid, &policy, &param);
/* sched_priority contains the priority of the thread */
priority = param.sched_priority;

pthread_getschedparam返回值
pthread_getschedparam()在成功完成之后返回零。其他任何返回值都表示出现了错误。如果出现以下情况,该函数将失败并返回对应的值。
ESRCH
描述: tid指定的值不引用现有的线程。
向线程发送信号
请使用pthread_kill(3C)向线程发送信号。
pthread_kill语法
int pthread_kill(thread_t tid, int sig);

#include <pthread.h>
#include <signal.h>
int sig;
pthread_t tid;
int ret;
ret = pthread_kill(tid, sig);

pthread_kill()将信号sig发送到由tid指定的线程。tid所指定的线程必须与调用线程在同一个进程中。sig参数必须来自signal(5)提供的列表。
如果sig为零,将执行错误检查,但并不实际发送信号。此错误检查可用来检查tid的有效性。
pthread_kill返回值
pthread_kill()在成功完成之后返回零。其他任何返回值都表示出现了错误。如果出现以下任一情况,pthread_kill()将失败并返回相应的值。
EINVAL
描述: sig是无效的信号量。
ESRCH
描述: 当前的进程中找不到tid。
访问调用线程的信号掩码
请使用pthread_sigmask(3C)更改或检查调用线程的信号掩码。
pthread_sigmask语法
int pthread_sigmask(int how, const sigset_t *new, sigset_t *old);

#include <pthread.h>
#include <signal.h>
int ret;
sigset_t old, new;
ret = pthread_sigmask(SIG_SETMASK, &new, &old);
 /* set new mask */
ret = pthread_sigmask(SIG_BLOCK, &new, &old); 
/* blocking mask */
ret = pthread_sigmask(SIG_UNBLOCK, &new, &old);
 /* unblocking */

how用来确定如何更改信号组。how可以为以下值之一:
·SIG_BLOCK。向当前的信号掩码中添加new,其中new表示要阻塞的信号组。
·SIG_UNBLOCK。从当前的信号掩码中删除new,其中new表示要取消阻塞的信号组。
·SIG_SETMASK。将当前的信号掩码替换为new,其中new表示新的信号掩码。
当new的值为NULL时,how的值没有意义,线程的信号掩码不发生变化。要查询当前已阻塞的信号,请将NULL值赋给new参数。除非old变量为NULL,否则old指向用来存储以前的信号掩码的空间。
pthread_sigmask返回值
pthread_sigmask()在成功完成之后返回零。其他任何返回值都表示出现了错误。如果出现以下情况,pthread_sigmask()将失败并返回相应的值。
EINVAL
描述: 未定义how的值。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值