POSIX 线程在一个进程和一个地址空间内提供并发执行。共享地址空间并不意味着共享可变状态是安全的:必须通过互斥锁、条件变量或 C 原子操作建立所有权和内存可见性。
创建、终止与取消 #
pthread_create 启动 void *(*start_routine)(void *),并向其传递一个指针参数。它直接返回错误号,而不是通过 errno 返回。线程可以通过从启动例程返回、调用 pthread_exit 或响应取消请求来终止;返回等价于使用该返回值调用 pthread_exit。调用 exit 或从 main 返回会终止整个进程,而初始线程调用 pthread_exit 时,其他线程会继续运行。
可连接线程会一直保留其退出值和资源,直到另一个线程成功调用 pthread_join。分离线程会在终止时释放这些资源,因此不能被连接。由此,每个已创建的线程都需要明确由某个线程负责连接或分离。线程不得连接自身,应用逻辑还必须确保只有一个线程连接给定的目标线程。
void *worker(void *arg) {
return arg;
}
pthread_t thread;
int error = pthread_create(&thread, NULL, worker, value);
if (error == 0) {
void *result;
error = pthread_join(thread, &result);
}取消默认处于启用且延迟处理状态。pthread_cancel 只是请求取消,并不保证立即终止。被指定为取消点的调用(包括条件等待)可以处理该请求。在跨越取消点获取资源的代码中,应安装 pthread_cleanup_push 处理程序,或以其他方式建立清理规则;对于会操作不变量的代码,异步取消并不适用。
属性与资源上限 #
如果创建线程时需要非默认行为,应初始化 pthread_attr_t,并在 pthread_create 返回后销毁属性对象。pthread_attr_setdetachstate 用于选择创建可连接线程还是分离线程。pthread_attr_setstacksize、pthread_attr_setstack 和 pthread_attr_setguardsize 控制栈分配与保护页;应用程序提供的栈必须保持映射状态,并在该线程终止前只能由该线程使用。
调度继承、调度策略、优先级参数和竞争范围也属于线程属性。对所请求调度策略的支持以及设置该策略所需的权限取决于具体实现。应将 pthread_attr_setaffinity_np 等 Linux 专用接口隔离在平台边界之后。每个线程都会消耗栈地址空间和运行时元数据,因此无上限地为每个请求创建线程会导致资源耗尽。
互斥锁与条件变量 #
条件变量表示受互斥锁保护的谓词发生变化,而不是表示谓词本身。应在持有互斥锁时检查谓词,在循环中等待,在仍持有同一互斥锁时将谓词设为真或假,然后发出信号或广播。
pthread_mutex_lock(&mutex);
while (!ready)
pthread_cond_wait(&condition, &mutex);
consume();
pthread_mutex_unlock(&mutex);pthread_cond_wait 会原子地释放互斥锁,并开始等待另一个获取互斥锁并向条件发出信号的线程。它在返回前重新获取互斥锁。这个原子交接可以防止谓词检查与阻塞之间发生的谓词更新丢失。循环仍然是必要的,因为唤醒可能是虚假的,而且在被唤醒的线程重新获取互斥锁之前,另一个消费者可能会改变谓词。
pthread_cond_timedwait 接受一个绝对截止时间。默认时钟是 CLOCK_REALTIME;如果必须避免墙上时钟调整影响超时,应在初始化前将条件属性的时钟设置为 CLOCK_MONOTONIC。超时或取消并不会免除函数重新获取互斥锁后释放该锁的义务。
互斥锁解锁与之后一次成功的加锁建立了发布受保护状态所需的同步关系。条件信号不能替代互斥锁,对非原子共享对象进行无同步读取仍然是数据竞争。只有在明确设计了内存顺序协议时,才应使用原子操作。
进程共享对象 #
PTHREAD_PROCESS_SHARED 要求实现使互斥锁或条件变量能够跨进程使用。对象及其关联状态必须位于真正共享的映射中,例如通过 shm_open 加 MAP_SHARED 创建的映射,而不能位于分别分配、仅具有相同虚拟地址的内存中。由于某些对象类型和环境可能不支持进程共享,因此应检查属性设置和初始化错误。在任何线程或进程都不可能继续使用互斥锁或条件变量之前,不得销毁它们。
POSIX 条件变量规范和 pthreads(7) 规定了该 API 及其在 Linux 上的行为。
评论
在 GitHub 上阅读或评论(发表评论需要登录)