7.1 KiB
7.1 KiB
行,这一块我直接给你一份“能从 0 写到生产级”的 pthread 全量体系,不搞碎片,直接一屏尽量塞满核心知识 + 可运行代码骨架。你看完基本可以自己写多线程程序 + 同步原语 + 调试了。
一、pthread 是什么(本质)
POSIX Threads(pthread)= 用户态 API + 内核线程(Linux NPTL实现)
本质模型:
- 每个 pthread ≈ 一个内核调度实体(LWP)
- 共享:地址空间 / 全局变量 / 堆
- 独立:栈 / 寄存器 / 线程ID / 调度状态
二、最小可运行 pthread 程序(核心骨架)
#include <stdio.h>
#include <pthread.h>
void* thread_func(void* arg) {
int val = *(int*)arg;
printf("Thread got: %d\n", val);
return (void*) (long)(val * 2);
}
int main() {
pthread_t tid;
int arg = 10;
pthread_create(&tid, NULL, thread_func, &arg);
void* ret;
pthread_join(tid, &ret);
printf("Thread return: %ld\n", (long)ret);
return 0;
}
编译:
gcc main.c -o main -pthread
关键点:
- pthread_create → 创建线程
- pthread_join → 回收线程(类似 wait)
- 函数签名必须:
void* (*)(void*)
三、线程创建:pthread_create(核心接口)
int pthread_create(
pthread_t *thread,
const pthread_attr_t *attr,
void *(*start_routine)(void *),
void *arg
);
关键理解:
- thread:输出线程ID
- attr:线程属性(栈大小 / detached等)
- start_routine:线程入口函数
- arg:传入参数(只能一个 → 用 struct)
四、线程终止(3种方式)
1. return
return value;
2. pthread_exit
pthread_exit((void*)value);
3. 主线程退出影响
exit(0); // 杀死整个进程
pthread_exit(0); // 主线程结束,但子线程继续
五、pthread_join vs detach(非常重要)
join(默认)
pthread_join(tid, &ret);
- 阻塞等待线程结束
- 回收资源(必须,否则泄漏)
detach(分离线程)
pthread_detach(tid);
或:
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
特点:
- 自动回收
- 不能 join
- 常用于后台线程
六、线程属性 pthread_attr_t(控制线程行为)
pthread_attr_t attr;
pthread_attr_init(&attr);
// 设置栈大小
pthread_attr_setstacksize(&attr, 1024 * 1024);
// 设置 detached
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_create(&tid, &attr, func, NULL);
pthread_attr_destroy(&attr);
七、线程同步核心:为什么需要?
多个线程:
- 共享内存 → 数据竞争(race condition)
- CPU乱序 / 编译优化 → 不可预测
必须同步!
八、互斥锁(Mutex)——最核心
使用流程
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock(&lock);
// 临界区
pthread_mutex_unlock(&lock);
完整例子(避免竞态)
#include <stdio.h>
#include <pthread.h>
int counter = 0;
pthread_mutex_t lock;
void* worker(void* arg) {
for (int i = 0; i < 100000; i++) {
pthread_mutex_lock(&lock);
counter++;
pthread_mutex_unlock(&lock);
}
return NULL;
}
int main() {
pthread_t t1, t2;
pthread_mutex_init(&lock, NULL);
pthread_create(&t1, NULL, worker, NULL);
pthread_create(&t2, NULL, worker, NULL);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
printf("counter = %d\n", counter);
pthread_mutex_destroy(&lock);
}
mutex 本质(你要理解这个)
- lock → 内核futex(用户态自旋 + 内核阻塞)
- 竞争少:用户态解决
- 竞争多:进入内核 sleep
九、读写锁(rwlock)
pthread_rwlock_t rwlock;
pthread_rwlock_init(&rwlock, NULL);
pthread_rwlock_rdlock(&rwlock); // 多读
pthread_rwlock_wrlock(&rwlock); // 独占写
pthread_rwlock_unlock(&rwlock);
适合:
- 读多写少
十、条件变量(Condition Variable)——线程通信核心
模型:生产者消费者
pthread_mutex_t lock;
pthread_cond_t cond;
int ready = 0;
void* consumer(void* arg) {
pthread_mutex_lock(&lock);
while (!ready) {
pthread_cond_wait(&cond, &lock);
}
printf("Consumed\n");
pthread_mutex_unlock(&lock);
}
生产者:
pthread_mutex_lock(&lock);
ready = 1;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);
核心语义(重点)
pthread_cond_wait(&cond, &lock);
等价于:
- unlock(lock)
- sleep
- 被唤醒
- lock(lock)
⚠️ 必须 while 而不是 if(防止虚假唤醒)
十一、信号量(POSIX sem)
#include <semaphore.h>
sem_t sem;
sem_init(&sem, 0, 1); // 1 = mutex
sem_wait(&sem);
sem_post(&sem);
十二、自旋锁(spinlock)
pthread_spinlock_t spin;
pthread_spin_init(&spin, PTHREAD_PROCESS_PRIVATE);
pthread_spin_lock(&spin);
// busy wait
pthread_spin_unlock(&spin);
适合:
- 临界区极短
- 不想进入内核
十三、线程局部存储(TLS)
pthread_key_t key;
pthread_key_create(&key, NULL);
pthread_setspecific(key, value);
void* val = pthread_getspecific(key);
本质:
- 每个线程一份变量(类似 __thread)
十四、线程取消(高级)
pthread_cancel(tid);
线程需要:
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
pthread_testcancel();
十五、常见坑(你必须知道)
- ❌ 传栈变量地址
int x;
pthread_create(..., &x); // 线程可能读到脏数据
✔ 解决:
- malloc / struct
- ❌ 忘记 join → 内存泄漏
- ❌ 死锁
T1: lock(A) → lock(B)
T2: lock(B) → lock(A)
- ❌ double lock
- ❌ cond 没用 while
十六、完整“工业级”线程模型(模板)
typedef struct {
int id;
pthread_mutex_t* lock;
} Task;
void* worker(void* arg) {
Task* t = (Task*)arg;
pthread_mutex_lock(t->lock);
printf("Thread %d working\n", t->id);
pthread_mutex_unlock(t->lock);
return NULL;
}
int main() {
pthread_t tids[4];
pthread_mutex_t lock;
pthread_mutex_init(&lock, NULL);
Task tasks[4];
for (int i = 0; i < 4; i++) {
tasks[i].id = i;
tasks[i].lock = &lock;
pthread_create(&tids[i], NULL, worker, &tasks[i]);
}
for (int i = 0; i < 4; i++) {
pthread_join(tids[i], NULL);
}
pthread_mutex_destroy(&lock);
}
十七、你可以继续往下学的方向(建议)
如果你要深入(你现在这个水平完全可以):
- pthread + epoll → 高性能服务器
- 线程池实现(非常关键)
- work queue / task queue
- lock-free(CAS + 原子操作)
- 内存模型(happens-before)
如果你要,我下一步可以直接给你:
- 手写线程池(工业级实现)
- pthread + epoll 写一个 Web Server
- 从 pthread 过渡到 C++ std::thread / async(对比底层)
你现在这个进度,已经在往系统级工程走了,这块搞透基本就是“写操作系统级程序”的门槛。