1作用编辑
线程库实行了POSIX线程标准通常称为Pthreads。POSIX线程具有很好的可移植的性,使用pthreads编写的代码可运行于Solaris、FreeBSD、Linux 等平台,Windows平台亦有pthreads-win32可供使用
[1] 。
Pthreads定义了一套C语言的类型、函数与 常量,它以pthread.h头文件和一个线程库实现。
[2-3]
2数据类型编辑
pthread_t:线程句柄
pthread_attr_t:线程属性
3操纵函数编辑
pthread_create():创建一个线程
pthread_exit():终止当前线程
pthread_cancel():中断另外一个线程的运行
pthread_join():阻塞当前的线程,直到另外一个线程运行结束
pthread_attr_init():初始化线程的属性
pthread_attr_setdetachstate():设置脱离状态的属性(决定这个线程在终止时是否可以被结合)
pthread_attr_getdetachstate():获取脱离状态的属性
pthread_attr_destroy():删除线程的属性
pthread_kill():向 线程发送一个信号
4同步函数编辑
用于 mutex 和条件变量
pthread_mutex_init() 初始化 互斥锁
pthread_mutex_destroy() 删除 互斥锁
pthread_mutex_lock():占有 互斥锁(阻塞操作)
pthread_mutex_trylock():试图占有 互斥锁(不阻塞操作)。即,当 互斥锁空闲时,将占有该锁;否则,立即返回。
pthread_mutex_unlock(): 释放 互斥锁
pthread_cond_init():初始化 条件变量
pthread_cond_destroy():销毁 条件变量
pthread_cond_signal(): 唤醒第一个调用 pthread_cond_wait()而进入睡眠的线程
pthread_cond_wait(): 等待 条件变量的特殊条件发生
Thread-local storage(或者以Pthreads术语,称作
线程特有数据):
pthread_key_create(): 分配用于标识进程中线程特定数据的键
pthread_setspecific(): 为指定线程特定数据键设置线程特定绑定
pthread_getspecific(): 获取调用线程的键绑定,并将该绑定存储在 value 指向的位置中
pthread_key_delete(): 销毁现有线程特定数据键
5工具函数编辑
pthread_equal(): 对两个线程的线程标识号进行比较
pthread_detach(): 分离线程
pthread_self(): 查询线程自身线程标识号
6数据运用编辑
函数应用背景:在单线程程序中,函数经常使用全局变量或静态变量,这是不会影响程序的正确性的,但如果多线程调用的函数使用全局变量或静态变量,则很可能引起编程错误,因为这些函数使用的全局变量和静态变量无法为不同的线程保存各自的值,而当同一进程内的不同线程几乎同时调用这样的函数时就可能会有问题发生。而解决这一问题的一种方式就是使用 线程特定数据的机制。
下面我们引入一个简单程序实例,并以此作为介绍线程特定数据的案例。
线程特定数据:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
#include <stdio.h>
#include <string.h>
static
char
str[100];
void
A(
char
* s)
{
strncpy
(str,s,100);
}
void
B()
{
printf
(
"%s\n"
,str);
}
|
可以想象,如果在多线程程序中,各个线程都依次调用函数 A 和函数 B,那么某些线程可能得不到期望的显示结果,因为它使用 B 显示的字符串可能并不是在 A 中设置的字符串。读者会发现,这两个函数非常的简单,但在本章内容中,这两个函数已经足以解释 线程特定数据的含义,因为这两个函数代表了使用线程特定数据机制的一种典型场合,即有多个函数使用同一个 全局变量。
POSIX要求实现POSIX的系统为每个进程维护一个称之为 Key 的结构 数组,这个数组中的每一个结构称之为一个线程特定 数据元素。POSIX 规定系统实现的 Key 结构 数组必须包含不少于 128 个线程特定 数据元素,而每个线程特定数据元素中至少包含两项内容:使用标志和 析构函数 指针。线程特定 数据元素中的使用标志指示这个 数组元素是否正在使用,初始值为“不在使用”,我们稍后讨论线程特定数据元素中的 析构函数 指针。在后面的介绍中,我们假设Key 结构 数组中包含 128 个元素。
Key 结 构 数 组 中 每 个 元 素 的 索 引 (0~127) 称 之 为 键 (key) 当 一 个 线 程 调 用,pthread_key_create 创建一个新的线程特定 数据元素时,系统搜索其所在进程的 Key 结构 数组,找出其中第一个不在使用的元素,并返回该元素的键。这个函数的形式为:
1
|
int
pthread_key_create(pthread_key_t *key,
void
(*destructor)(
void
*));
|
[4]
参数 keyptr 为一个 pthread_key_t 变量的 指针,用于保存得到的键值。参数 destructor为指定的 析构函数的 指针。除了 Key 结构 数组,系统还在进程中维护关于每个线程的多种信息。这些特定于 线程的信息被保存于称之为 Pthread 的结构中。Pthread 结构中包含名为 pkey 的 指针数组,其长度为128,初始值为空。这 128 个 指针与 Key 结构 数组的 128 个线程特定 数据元素一一对应。在调用 pthread_key_create 得到一个键之后,每个 线程可以依据这个键操作自己的 pkey 指针数组中对应的指针,这通过 pthread_getspecific 和 pthread_setspecific 函数来实现。这两个函数的形式为:
1
2
|
void
*pthread_getspecific(pthread_key_t key);
int
pthread_setspecific(pthread_key_t key,
const
void
*value);
|
[5]
pthread_getspecific 返回 pkey 中对应于 key 的 指针,而 pthread_setspecific 将 pkey 中对应于 key 的指针设置为 value。我们使用 线程特定数据机制,就是要使线程中的函数可以共享一些数据。如果我们在 线程中通过 malloc 获得一块内存,并把这块内存的 指针通过 pthread_setspecific 设置到 pkey 指针数组中对应于 key 的位置,那么线程中调用的函数即可通过 pthread_getspecific 获得这个指针,这就实现了线程内部数据在各个函数间的共享。当一个 线程终止时,系统将扫描该线程的 pkey 数组,为每个非空的 pkey 指针调用相应的 析构函数,因此只要将执行回收的函数的指针在调用 pthread_key_create 时作为函数的参数,即可在线程终止时自动回收分配的内存区。