1. 线程同步与条件变量:从数据竞争到公平调度
在Linux多线程编程中,互斥量(Mutex)是解决数据竞争问题的基本工具。但我在实际项目中发现,单纯使用互斥量会导致一个典型问题:线程调度的不公平性。具体表现为某个线程可能长期独占资源,而其他线程处于"饥饿"状态。
1.1 互斥量的局限性分析
以售票系统为例,当多个线程同时访问票数变量时,使用互斥量确实能避免数据竞争。但我在压力测试中发现,系统经常出现"只有一个线程处理所有售票任务"的情况。通过日志分析,发现原因主要有三:
- 锁竞争的不公平性:线程释放锁后可能立即重新获取,形成"锁霸占"
- 调度策略影响:Linux默认的CFS调度器可能优先调度刚释放锁的线程
- 缺乏等待机制:线程在无法获取资源时持续竞争,浪费CPU周期
cpp复制// 典型的问题代码示例
pthread_mutex_lock(&mutex);
if(ticket_count > 0) {
// 处理售票
ticket_count--;
}
pthread_mutex_unlock(&mutex);
1.2 条件变量的引入与原理
条件变量(Condition Variable)正是为解决这类问题而设计。它允许线程在条件不满足时主动休眠,避免无效的锁竞争。其核心思想是:"当条件不成立时,让出CPU而不是死等"。
条件变量需要与互斥量配合使用,形成以下工作流程:
- 获取互斥锁
- 检查条件
- 条件不满足时,调用pthread_cond_wait进入等待
- 其他线程修改条件后,通过signal/broadcast唤醒等待线程
关键提示:pthread_cond_wait会原子性地释放互斥锁并进入等待,这是避免竞态条件的关键设计
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 条件变量的实战应用
2.1 基础API详解
2.1.1 初始化与销毁
条件变量有两种初始化方式:
cpp复制// 动态初始化(推荐)
pthread_cond_t cond;
pthread_cond_init(&cond, NULL);
// 静态初始化
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
销毁时需注意:
- 确保没有线程在等待该条件变量
- 静态初始化的条件变量无需销毁
- 销毁后再次使用会导致未定义行为
2.1.2 等待与唤醒机制
pthread_cond_wait的内部工作原理:
- 原子性地释放互斥锁
- 将线程加入条件变量的等待队列
- 线程进入休眠状态
- 被唤醒后重新获取互斥锁
对应的唤醒操作:
cpp复制// 唤醒单个线程(效率更高)
pthread_cond_signal(&cond);
// 唤醒所有等待线程
pthread_cond_broadcast(&cond);
``
