一、并发编程概述:从单核到多核的思维跃迁
各位同学,欢迎来到《C语言并发编程实战》的第一章。
先问大家一个问题:你写过的C程序,有没有遇到过“卡死”、“响应慢”、“数据莫名其妙就错了”的情况?
嗯,我猜十有八九遇到过。我自己刚入行那会儿,就栽过一个大跟头——一个网络服务程序,跑着跑着就“假死”了,CPU占用率却飙到100%。查了三天,最后发现是并发控制没做好,两个线程同时修改了一个全局变量。
从那天起,我就明白了一个道理:并发编程,不是“锦上添花”,而是“必修课”。尤其现在多核处理器普及了,你写的程序如果还是单线程跑,那简直是暴殄天物。
1.1 什么是并发?
说白了,并发就是“同时处理多件事情的能力”。
举个例子:你一边写代码,一边听音乐,偶尔还回个微信。这三件事在“交替进行”,但给人的感觉是“同时发生”。这就是并发——逻辑上的同时。
在计算机里,并发意味着:多个任务在同一个时间段内启动、运行、完成。它们可能不是真正的“同时执行”,而是通过时间片轮转,让每个任务都有机会跑一跑。
核心要点:并发关注的是“任务的分解与调度”,而不是“物理上是否同时执行”。
1.2 并发 vs 并行:别再傻傻分不清
这两个词,我见过太多人混用了。包括一些工作三五年的工程师,面试时也说不清楚。
我习惯这么理解:
- 并发(Concurrency):多个任务“交替执行”,看起来像同时。就像一个人同时做三件事——其实是来回切换。
- 并行(Parallelism):多个任务“真正同时执行”。就像三个人各做一件事——互不干扰。
你想想看:单核CPU能并行吗?不能。它只能并发。多核CPU才能并行。
但注意了——并发是结构问题,并行是执行问题。一个程序可以设计成并发的结构,但运行在单核上,它只是并发;运行在多核上,它才可能并行。
| 维度 | 并发 | 并行 |
|---|---|---|
| 核心 | 任务分解与调度 | 任务同时执行 |
| 硬件依赖 | 单核即可 | 需要多核 |
| 关注点 | 逻辑上的同时 | 物理上的同时 |
| 类比 | 一个人切菜、炒菜、煮汤来回切换 | 三个人分别切菜、炒菜、煮汤 |
我的经验:设计程序时,先考虑“并发结构”——把任务拆成独立单元。至于能不能并行,那是硬件的事。但结构设计好了,并行自然水到渠成。
1.3 C语言中的并发支持
C语言本身,其实没有内置的并发支持。它是一门“古老”的语言,诞生于单核时代。
但别急——C语言有强大的操作系统接口和库支持。我们常用的并发手段有:
- POSIX 线程(pthreads):Linux/Unix 下的标准线程库。我90%的并发项目都用它。
- C11 标准中的
<threads.h>:C语言官方标准引入的线程支持。但说实话,用的人不多,生态不够成熟。 - OpenMP:用于共享内存并行编程的API。适合科学计算,简单易用。
- 原子操作(Atomic Operations):C11 提供了
<stdatomic.h>,用于无锁编程。 - 信号量、互斥锁、条件变量:这些是同步原语,pthreads 都提供了。
举个例子,一个最简单的pthreads程序:
#include <pthread.h>
#include <stdio.h>
void* print_message(void* arg) {
printf("Hello from thread!\n");
return NULL;
}
int main() {
pthread_t thread;
pthread_create(&thread, NULL, print_message, NULL);
pthread_join(thread, NULL);
return 0;
}
这段代码创建了一个线程,打印一句话,然后退出。看起来简单吧?但背后涉及线程创建、调度、同步等一堆概念。我们后面会一一拆解。
注意:我曾经见过有人把pthread_create放在循环里,一次创建几百个线程,结果系统直接挂了。线程不是越多越好,线程数一般建议不超过CPU核心数的2倍(I/O密集型可以适当多些)。
1.4 课程目标与学习路径
这门课的目标很明确:让你能写出正确、高效、可维护的并发C程序。
具体来说,学完这门课,你应该能:
- 理解并发编程的核心概念(线程、同步、死锁、竞态条件等)
- 熟练使用pthreads进行多线程编程
- 掌握常见的同步机制(互斥锁、条件变量、信号量、读写锁)
- 能分析并解决并发程序中的典型问题(数据竞争、死锁、活锁)
- 了解一些高级话题(无锁编程、内存模型、并发设计模式)
学习路径我建议这样走:
- 打好基础:先搞懂线程、进程、并发、并行这些基本概念(就是本章内容)
- 动手实践:从简单的pthreads例子开始,写几个多线程程序
- 深入同步:重点攻克互斥锁、条件变量、信号量——这是并发编程的“硬骨头”
- 避坑实战:学习死锁、竞态条件的识别与避免
- 进阶提升:了解无锁编程、内存模型、并发设计模式
下面这张图,概括了本章的知识体系:
我的建议:别一上来就啃《深入理解计算机系统》那种大部头。先动手写代码,遇到问题再回头查理论。我当年就是靠“写一个多线程下载器”入的门——边写边学,印象最深。
好了,第一章就到这里。记住一句话:并发编程不是魔法,是工程。后面我们会一步步拆解,从线程创建到同步机制,从死锁避免到性能优化。每一步我都会结合自己的踩坑经历来讲。
准备好了吗?我们第二章见。