pthread_create必须用正确签名void()(void*),参数错会导致运行时崩溃;不join或detach会内存泄漏;mutex漏unlock必死锁;cond_wait必须用while防虚假唤醒。

pthread_create 怎么用?参数传错会怎样?
创建线程必须用 pthread_create,不是 thread_create 或别的名字。它有四个参数:线程ID指针、属性、入口函数、函数参数。最容易出错的是第3个参数——入口函数签名必须是 void* (*)(void*),返回 void* 且只接受一个 void* 参数;如果写成 int func() 或 void func(int),编译可能过(尤其开了 -Wno-format),但运行时栈会被破坏,现象是子线程一执行就 crash 或输出乱码。
- 线程函数不能是局部变量地址(比如直接传 &i),因为主线程 return 后栈帧销毁,子线程访问就是野指针
- 若不需要传参,第4个参数传
NULL,别传0或未初始化指针 - 成功返回 0,失败不返回 -1,而是返回错误码(如
EAGAIN、EINVAL),必须检查返回值,不能只看是否为 NULL
pthread_join 和 pthread_detach 的区别与误用场景
pthread_join 是阻塞等待线程结束并回收资源;pthread_detach 是把线程设为“分离态”,结束后系统自动清理。两者互斥:对一个线程既调 join 又调 detach 会导致未定义行为(常见 segfault);对已 join 过的线程再 join,行为未定义(glibc 通常 abort)。
- 不调
join也不detach→ 线程退出后变成“僵尸线程”,资源(栈、TCB)不释放,长期运行会内存泄漏 - 主线程 exit() 前没处理子线程 → 整个进程终止,子线程强制结束,
pthread_cleanup_push注册的清理函数可能不执行 - 想让线程后台运行且不关心结果,用
pthread_detach;想等结果或做善后,必须用pthread_join
mutex 锁住什么?为什么只加锁不 unlock 会卡死?
pthread_mutex_t 锁的是临界区逻辑,不是变量本身。它靠程序员显式调用 pthread_mutex_lock/pthread_mutex_unlock 来界定哪段代码不能并发执行。漏掉 unlock 是最常见死锁源头——别的线程在 lock 处永久阻塞,整个程序 hang 住,且 gdb 看堆栈永远停在 futex_wait。
- 锁粒度要小:不要把
printf或文件 I/O 包进临界区,否则严重拖慢并发性能 - 避免嵌套锁:A 锁了 mutex1 再去 lock mutex2,B 反过来,就容易循环等待
- 初始化必须用
PTHREAD_MUTEX_INITIALIZER或pthread_mutex_init,全局/静态 mutex 用前者更安全;用完记得pthread_mutex_destroy(尤其在反复创建销毁线程的场景)
条件变量 wait 为什么必须配合 while 而不是 if?
pthread_cond_wait 被唤醒后,**不保证条件真的成立**。可能被虚假唤醒(spurious wakeup),也可能多个线程被 signal 唤醒后竞争锁,只有第一个拿到锁的能真正干活,其余仍需重新判断条件。所以必须写成 while (!condition) pthread_cond_wait(...),而不是 if。
立即学习“C语言免费学习笔记(深入)”;
- 典型错误:子线程
cond_signal后主线程只if (flag == 1)就往下走,结果 flag 已被其他线程改回 0,逻辑错乱 -
pthread_cond_wait内部会自动释放 mutex,并在唤醒后重新获取——这个“原子性”是它唯一保证,别指望它帮你校验业务状态 - 务必确保 signal 和 wait 在同一 mutex 保护下操作共享条件变量,否则存在竞态:signal 发生在 wait 进入阻塞前,就会丢失信号
多线程里最危险的不是 crash,而是偶尔复现的数据错乱——它不会报错,只会让你在上线后花三天查一个 ++counter 没加锁的 bug。










