一文打尽pthread库

一文打尽pthread库

pthread(POSIX Threads)是遵循 POSIX 标准的线程库,广泛用于 Unix/Linux 系统中实现多线程编程。它提供了一组 C 语言 API,用于创建、管理、同步线程。以下是对 pthread 库及相关函数的系统性总结:


一、基本概念

  • 线程(Thread):轻量级进程,共享进程地址空间,独立执行流。
  • 主线程:程序启动时默认创建的线程。
  • 并发 vs 并行:并发是逻辑上同时执行,并行是物理上同时执行(多核)。
  • 线程安全:函数/数据结构在多线程环境下能正确工作。

二、核心数据类型

#include <pthread.h>

pthread_t           // 线程标识符(类似进程的 pid)
pthread_attr_t      // 线程属性结构体
pthread_mutex_t     // 互斥锁
pthread_cond_t      // 条件变量
pthread_rwlock_t    // 读写锁

三、线程管理函数

1. 创建线程

int pthread_create(pthread_t *thread, 
                   const pthread_attr_t *attr,
                   void *(*start_routine)(void*), 
                   void *arg);
  • thread:输出参数,新线程 ID。
  • attr:线程属性,NULL 表示默认。
  • start_routine:线程入口函数。
  • arg:传递给入口函数的参数。
  • 返回值:0 成功,非 0 错误码(非 errno)。

⚠️ 注意:必须链接 -lpthread(或 -pthread


2. 等待线程结束(阻塞)

int pthread_join(pthread_t thread, void **retval);
  • 阻塞调用线程,直到目标线程结束。
  • 可获取线程返回值(通过 retval)。
  • 适用于需要同步或回收资源的场景。

3. 分离线程(非阻塞回收)

int pthread_detach(pthread_t thread);
  • 线程结束后自动释放资源,无需 pthread_join
  • 不能对已分离线程调用 pthread_join

4. 获取当前线程 ID

pthread_t pthread_self(void);

5. 比较线程 ID

int pthread_equal(pthread_t t1, pthread_t t2);
  • 返回非 0 表示相等。

6. 退出线程

void pthread_exit(void *retval);
  • 主动终止当前线程,可传递返回值。
  • 主线程调用 pthread_exit 不会终止整个进程(除非是最后一个线程)。

四、线程属性设置(可选)

int pthread_attr_init(pthread_attr_t *attr);
int pthread_attr_destroy(pthread_attr_t *attr);

// 设置分离状态
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
// detachstate: PTHREAD_CREATE_JOINABLE / PTHREAD_CREATE_DETACHED

// 设置栈大小
int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);

五、线程同步机制

1. 互斥锁(Mutex)

用于保护临界区,防止多个线程同时访问共享资源。

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // 静态初始化

int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex); // 非阻塞
int pthread_mutex_unlock(pthread_mutex_t *mutex);
int pthread_mutex_destroy(pthread_mutex_t *mutex);

🔒 使用模式:

pthread_mutex_lock(&mutex);
// 临界区代码
pthread_mutex_unlock(&mutex);

2. 条件变量(Condition Variable)

用于线程间通信,常与互斥锁配合使用,实现“等待某个条件成立”。

pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); // 阻塞等待
int pthread_cond_timedwait(...); // 带超时
int pthread_cond_signal(pthread_cond_t *cond); // 唤醒一个等待线程
int pthread_cond_broadcast(pthread_cond_t *cond); // 唤醒所有等待线程
int pthread_cond_destroy(pthread_cond_t *cond);

🔄 典型使用模式:

pthread_mutex_lock(&mutex);
while (condition_is_false) {
    pthread_cond_wait(&cond, &mutex); // 自动释放锁,被唤醒后重新加锁
}
// 执行操作
pthread_mutex_unlock(&mutex);

3. 读写锁(Read-Write Lock)

允许多个读者同时访问,写者独占访问。

pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;

int pthread_rwlock_init(...);
int pthread_rwlock_rdlock(...);    // 读锁
int pthread_rwlock_wrlock(...);    // 写锁
int pthread_rwlock_unlock(...);
int pthread_rwlock_destroy(...);

适合“读多写少”场景。


4. 自旋锁(Spinlock)【可选】

忙等待锁,适用于锁持有时间极短的场景。

pthread_spinlock_t spinlock;

int pthread_spin_init(...);
int pthread_spin_lock(...);
int pthread_spin_unlock(...);
int pthread_spin_destroy(...);

六、线程局部存储(TLS)

每个线程拥有独立的变量副本。

pthread_key_t key;

int pthread_key_create(pthread_key_t *key, void (*destructor)(void*));
int pthread_setspecific(pthread_key_t key, const void *value);
void *pthread_getspecific(pthread_key_t key);
int pthread_key_delete(pthread_key_t key);

类似于 C11 的 _Thread_local 或 GCC 的 __thread


七、取消机制(Cancellation)

允许一个线程请求终止另一个线程。

int pthread_cancel(pthread_t thread); // 发送取消请求

// 设置取消状态和类型
int pthread_setcancelstate(int state, int *oldstate);
// state: PTHREAD_CANCEL_ENABLE / PTHREAD_CANCEL_DISABLE

int pthread_setcanceltype(int type, int *oldtype);
// type: PTHREAD_CANCEL_DEFERRED(默认,到取消点) / PTHREAD_CANCEL_ASYNCHRONOUS

void pthread_testcancel(void); // 显式设置取消点

⚠️ 取消点(Cancellation Points):如 sleep, read, write, pthread_cond_wait 等阻塞函数。


八、一次初始化(One-time Initialization)

确保某段初始化代码只执行一次。

pthread_once_t once_control = PTHREAD_ONCE_INIT;

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

常用于初始化全局资源(如互斥锁、TLS key)。


九、常见错误处理

pthread 函数不设置 errno,而是直接返回错误码:

int ret = pthread_create(...);
if (ret != 0) {
    fprintf(stderr, "Error: %s\n", strerror(ret));
}

或使用 perror 需要先设置 errno:

errno = ret;
perror("pthread_create");

十、编译与链接

gcc -o program program.c -lpthread
# 或推荐使用:
gcc -o program program.c -pthread   # 自动定义宏、链接库

十一、最佳实践与注意事项

  1. 避免死锁:加锁顺序一致,避免嵌套锁。
  2. 资源回收:join 或 detach 所有线程,避免资源泄漏。
  3. 线程安全函数:避免使用非线程安全函数(如 strtok, rand → 改用 strtok_r, rand_r)。
  4. 信号处理:线程中慎用信号,推荐使用 sigwait 或指定信号处理线程。
  5. 性能考虑:锁粒度不宜过大,避免频繁加锁。
  6. 调试工具:使用 valgrind --tool=helgrindThreadSanitizer 检测竞争条件。

十二、简单示例

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>

void* thread_func(void* arg) {
    int id = *(int*)arg;
    printf("Thread %d running\n", id);
    sleep(1);
    pthread_exit((void*)(long)id);
}

int main() {
    pthread_t t1, t2;
    int id1 = 1, id2 = 2;

    pthread_create(&t1, NULL, thread_func, &id1);
    pthread_create(&t2, NULL, thread_func, &id2);

    void* retval;
    pthread_join(t1, &retval);
    printf("Thread 1 returned: %ld\n", (long)retval);

    pthread_join(t2, &retval);
    printf("Thread 2 returned: %ld\n", (long)retval);

    return 0;
}

总结

功能主要函数
创建线程pthread_create
等待线程pthread_join
分离线程pthread_detach
互斥锁pthread_mutex_*
条件变量pthread_cond_*
读写锁pthread_rwlock_*
线程局部存储pthread_key_*
一次初始化pthread_once
线程取消pthread_cancel, pthread_testcancel

掌握 pthread 库是进行 Linux/Unix 系统级并发编程的基础。合理使用同步机制、避免竞态条件和死锁,是编写健壮多线程程序的关键。


✅ 推荐学习顺序:线程创建 → 互斥锁 → 条件变量 → 读写锁 → 高级特性(TLS、取消、一次初始化)
📚 参考资料:《UNIX环境高级编程》、《POSIX标准文档》、Linux man pages (man pthread_create)

以下是《UNIX环境高级编程》和《POSIX标准文档》的官方或权威获取链接:


📘 1.《UNIX环境高级编程》(Advanced Programming in the UNIX Environment, 简称 APUE)

  • 作者:W. Richard Stevens & Stephen A. Rago
  • 当前最新版:第3版(2013),涵盖 POSIX.1-2008 和 UNIX System V / BSD 扩展
  • 官方出版商页面
    👉 https://www.apuebook.com/

该网站由作者 Stephen Rago 维护,提供:

  • 源代码下载(所有示例代码)
  • 勘误表(errata)
  • 各章摘要和更新说明
  • 非常适合配合学习使用
  • 购买纸质/电子书
  • Amazon:https://www.amazon.com/Advanced-Programming-UNIX-Environment-3rd/dp/0321637739
  • 中国读者可在京东、当当购买中文翻译版(译者:戚正伟 等)

⚠️ 本书无“开源免费电子版”,请支持正版。


📜 2.《POSIX 标准文档》(IEEE Std 1003.1)

POSIX 是由 IEEE 和 The Open Group 共同维护的标准,官方文档需通过其网站获取。

✅ 官方免费在线查阅版(HTML):

👉 The Open Group Base Specifications, Issue 7 (2018) — POSIX.1-2017
🔗 https://pubs.opengroup.org/onlinepubs/9699919799/

这是当前最权威、最新且免费公开访问的 POSIX 标准文档(含 Shell、Utilities、System Interfaces、Headers 等)。

  • 包含所有 pthread 函数规范(如 pthread_create, pthread_mutex_lock 等)
  • 可直接搜索函数名,查看标准定义、参数、返回值、错误码、可移植性说明
  • 支持书签、交叉引用,适合开发者查阅

📄 PDF 下载版(需注册,部分免费):

👉 https://publications.opengroup.org/standards/unix

  • 注册后可免费下载 PDF(部分文档需付费)
  • 搜索 “IEEE Std 1003.1™-2017” 或 “The Open Group Base Specifications Issue 7”

🆚 IEEE 官方标准购买页面(付费):

👉 https://standards.ieee.org/standard/1003_1-2017.html

  • IEEE 出版的正式标准文档(PDF)
  • 价格较高(约 $200+),适合企业或标准研究者
  • 内容与 The Open Group 版本基本一致

✅ 对于绝大多数开发者,The Open Group 免费在线版已完全足够


📌 补充:Linux man pages(在线)

虽然不是“标准文档”,但 Linux man pages 是最实用的函数参考:

🔗 https://man7.org/linux/man-pages/

  • 搜索 pthread_create → https://man7.org/linux/man-pages/man3/pthread_create.3.html
  • 包含函数原型、描述、示例、错误码、遵循标准(如 POSIX.1-2001)
  • 由 Michael Kerrisk(《The Linux Programming Interface》作者)维护,权威可靠

✅ 总结推荐

资源名称类型推荐链接备注
《APUE》官网图书配套https://www.apuebook.com/源码+勘误,必备
POSIX 标准在线文档官方标准https://pubs.opengroup.org/onlinepubs/9699919799/免费、权威、最新
Linux man-pages函数手册https://man7.org/linux/man-pages/实用开发参考
IEEE POSIX 标准购买付费标准https://standards.ieee.org/standard/1003_1-2017.html企业/研究用

📘 建议学习路径:

  1. 学 pthread → 查 man7.org 快速上手
  2. 深入理解标准行为 → 查 Open Group POSIX 文档
  3. 系统学习 UNIX 编程 → 读 APUE 第3版
此条目发表在linux文章分类目录。将固定链接加入收藏夹。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注