什么是线程同步?
想象一下超市收银台:如果所有顾客(线程)同时挤向同一个收银台(共享资源),场面会一片混乱。线程同步就是给顾客们发"排队号码牌",确保:
-
- 有序访问:每次只处理一个顾客
-
- 协调工作:收银员(CPU)高效服务
-
- 避免冲突:防止算错账(数据错误)
Linux提供5种"排队机制"解决多线程协作问题:

一、互斥锁(单人洗手间规则)
arduino
#include <pthread.h>
// 创建锁(相当于洗手间的"有人/无人"标识)
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
void* thread_task(void* arg) {
// 尝试进入(如果里面有人就排队等待)
pthread_mutex_lock(&lock);
/* 临界区开始(你的"私人时间") */
printf("Thread %d using resource\n", *(int*)arg);
sleep(1); // 模拟耗时操作
/* 临界区结束 */
// 开门出来(让下一位使用)
pthread_mutex_unlock(&lock);
return NULL;
}
适用场景:
- 文件写入操作
- 银行账户余额修改
- 任何需要"独享"资源的场景
特点:
- ✅ 简单易用
- ⚠️ 过度使用会降低并发性能
二、条件变量(咖啡厅取餐系统)
scss
pthread_cond_t order_ready = PTHREAD_COND_INITIALIZER;
pthread_mutex_t counter_lock = PTHREAD_MUTEX_INITIALIZER;
int order_number = 0;
// 顾客线程(等待取餐)
void* customer(void* arg) {
pthread_mutex_lock(&counter_lock);
while(order_number == 0) { // 必须用while循环检查
pthread_cond_wait(&order_ready, &counter_lock); // 放下锁等待通知
}
printf("Got order %d!\n", order_number);
pthread_mutex_unlock(&counter_lock);
return NULL;
}
// 厨师线程(通知取餐)
void* chef(void* arg) {
sleep(2); // 模拟做饭时间
pthread_mutex_lock(&counter_lock);
order_number = 123;
pthread_cond_signal(&order_ready); // 叫号通知顾客
pthread_mutex_unlock(&counter_lock);
return NULL;
}
工作流程:
-
- 顾客:锁定柜台 → 检查订单 → 等待叫号
-
- 厨师:完成订单 → 锁定柜台 → 更新订单 → 发送通知
-
- 顾客:被唤醒 → 重新检查 → 取餐
适用场景:
- 生产者-消费者模型(如消息队列)
- 线程间任务协调
三、自旋锁(抢车位)
scss
pthread_spinlock_t parking_lock;
// 初始化锁(停车场入口)
pthread_spin_init(&parking_lock, PTHREAD_PROCESS_PRIVATE);
void* driver(void* arg) {
// 开车绕圈找空位(CPU忙等待)
pthread_spin_lock(&parking_lock);
/* 停车成功(临界区) */
printf("Car %d parked\n", *(int*)arg);
// 开走释放车位
pthread_spin_unlock(&parking_lock);
return NULL;
}
适用场景:
- 极短操作(<0.1毫秒)
- 内核开发
- 实时系统
注意事项:
- ⚠️ 会浪费CPU资源
- ✅ 比互斥锁响应更快
锁类型对比表:
场景 | 推荐锁类型 | 类比 |
---|---|---|
短时间独占操作 | 自旋锁 | 快速便利店购物 |
长时间独占操作 | 互斥锁 | 餐厅包间用餐 |
多读少写 | 读写锁 | 图书馆 |
线程组协调 | 屏障 | 旅行团集合 |
事件通知 | 条件变量 | 咖啡厅叫号系统 |
参考文章: Linux线程同步入门指南