pthread_create需显式设置栈大小以防溢出,共享变量必须加锁避免竞态,线程退出后须pthread_join或pthread_detach清理资源,信号与多线程交互应避免pthread_kill而改用条件变量或事件通信。

pthread_create 启动线程时必须传入有效栈空间
很多初学者直接传 NULL 给 pthread_create 的第四个参数(线程属性),以为系统会自动分配,结果在线程函数里一用局部变量就崩溃。这不是随机错误,而是因为默认栈大小通常只有 2MB(Linux 下),且无法动态扩展;若线程递归过深或分配大数组(比如 char buf[1024*1024]),就会触发栈溢出,segfault 或静默破坏相邻内存。
实操建议:
- 避免在多线程中定义超大栈变量;改用
malloc分配堆内存,并确保线程退出前free - 如需更大栈,用
pthread_attr_setstacksize显式设置,例如:pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setstacksize(&attr, 8 * 1024 * 1024); // 8MB
pthread_create(&tid, &attr, thread_func, arg);
pthread_attr_destroy(&attr); - 注意:栈大小不能小于
PTHREAD_STACK_MIN(通常是 16KB),也不能超过系统限制(ulimit -s)
共享变量不加锁导致的竞态不是“偶尔出错”,而是必然不可预测
int counter = 0; 被两个线程同时执行 counter++,最终结果大概率是 1 而不是 2——这不是概率问题,是 counter++ 在汇编层面至少包含三步:读取、加 1、写回。两个线程可能交错执行这三步,造成一次更新被覆盖。
常见误判:
立即学习“C语言免费学习笔记(深入)”;
- “我只读不写,不用锁” → 错。即使只读,若另一线程正在写,你可能读到中间状态(非原子写入,尤其结构体或 64 位变量在 32 位平台)
- “我用 volatile 就安全了” → 错。
volatile只禁用编译器优化,不阻止 CPU 重排序,也不提供原子性或内存屏障 - “我 sleep 一下就能错开” → 错。这是典型的“靠运气编程”,在高负载或不同 CPU 架构下立即失效
正确做法:对共享变量的读写,统一用 pthread_mutex_t 保护;若只是计数,可考虑 __atomic_add_fetch(GCC 内置原子操作),但要注意平台兼容性。
本文档主要讲述的是OpenMP多线程编程指南;OpenMP是由OpenMP Architecture Review Board牵头提出的,并已被广泛接受的,用于共享内存并行系统的多线程程序设计的一套指导性注释(Compiler Directive)。OpenMP是一种面向共享内存以及分布式共享内存的多处理器多线程并行编程语言,能被用于显示指导多线程、共享内存并行的应用程序编程接口。希望本文档会给有需要的朋友带来帮助;感兴趣的朋友可以过来看看
线程退出后资源未清理:pthread_join 不是可选的
调用 pthread_create 后不调用 pthread_join,线程变成“分离状态”以外的“可连接线程”(joinable)。这类线程结束后,其退出状态、栈内存等资源不会自动释放,直到有其他线程调用 pthread_join。长期运行的程序若漏掉 pthread_join,会持续泄漏资源,最终 pthread_create 返回 EAGAIN(资源耗尽)。
两种处理路径:
- 主控线程明确等待子线程结束:创建后立刻或适当时机调用
pthread_join(tid, &retval) - 子线程自行分离:在子线程函数开头调用
pthread_detach(pthread_self()),之后无需join;但要注意,分离后不能再被join,也不能获取其返回值 - 切勿在主线程
exit()前遗漏join——exit会终止整个进程,未 join 的 joinable 线程资源仍不释放
信号与多线程交互极易出错,尽量避开 pthread_kill
用 pthread_kill(tid, SIGUSR1) 向某线程发信号,看似精准,实际风险极高:信号可能被任意线程接收(取决于信号掩码和调度),且若目标线程正阻塞在 read 或 pthread_cond_wait 上,行为不可控;更严重的是,signal 处理函数是全局的,多个线程同时收到同信号,会共用同一个 handler,引发数据竞争。
替代方案更可靠:
- 用
pthread_cond_signal+pthread_mutex_t实现线程间通知(推荐) - 用管道(pipe)或 eventfd(Linux)做跨线程事件通信,主循环用
poll等待 - 真需要信号,应使用
sigwait在指定线程中同步等待,且提前用pthread_sigmask屏蔽其他线程接收该信号
信号与线程模型本身不正交,C 标准库对多线程信号的支持非常有限,能不用就别碰。









