当前位置: 首页 > news >正文

线程同步:互斥锁与条件变量实战指南

目录

一、线程同步的必要性

1. 竞态条件(Race Condition)

2. 同步机制的作用

二、互斥锁(pthread_mutex)

1. 函数原型与操作

2. 示例:保护共享变量

3. 注意事项

三、条件变量(pthread_cond)

1. 函数原型与操作

2. 示例:生产者-消费者模型

3. 注意事项

四、互斥锁与条件变量的区别

五、常见问题与解决方案

1. 死锁问题

2. 条件变量未唤醒

六、总结


一、线程同步的必要性

1. 竞态条件(Race Condition)

  • 问题:多个线程并发访问共享资源(如变量、数据结构),导致结果不可预测。
  • 示例:两个线程同时对全局变量 count 执行 count++,最终值可能小于预期。

2. 同步机制的作用

  • 互斥锁(Mutex):确保同一时刻只有一个线程访问共享资源。
  • 条件变量(Condition Variable):协调线程间的等待与唤醒(如生产者-消费者模型)。

二、互斥锁(pthread_mutex

1. 函数原型与操作

函数作用
pthread_mutex_init初始化互斥锁(静态或动态)。
pthread_mutex_lock加锁。若锁已被占用,则阻塞等待。
pthread_mutex_unlock解锁。允许其他线程访问共享资源。
pthread_mutex_destroy销毁互斥锁,释放资源。

2. 示例:保护共享变量

#include <stdio.h>
#include <pthread.h>int count = 0;
pthread_mutex_t lock;void* increment(void* arg) {for (int i = 0; i < 100000; i++) {pthread_mutex_lock(&lock);  // 加锁count++;pthread_mutex_unlock(&lock); // 解锁}return NULL;
}int main() {pthread_t t1, t2;// 初始化互斥锁pthread_mutex_init(&lock, NULL);pthread_create(&t1, NULL, increment, NULL);pthread_create(&t2, NULL, increment, NULL);pthread_join(t1, NULL);pthread_join(t2, NULL);printf("Final count: %d\n", count); // 预期输出 200000// 销毁互斥锁pthread_mutex_destroy(&lock);return 0;
}

3. 注意事项

  • 死锁(Deadlock)
    • 同一线程重复加锁未解锁。
    • 解决方法:始终按固定顺序加锁,或使用递归锁(PTHREAD_MUTEX_RECURSIVE)。
  • 错误处理:检查所有函数返回值(如 pthread_mutex_lock 返回 EDEADLK 表示死锁)。

三、条件变量(pthread_cond

1. 函数原型与操作

函数作用
pthread_cond_init初始化条件变量。
pthread_cond_wait等待条件满足(会自动释放锁,等待时阻塞)。
pthread_cond_signal唤醒一个等待的线程。
pthread_cond_broadcast唤醒所有等待的线程。
pthread_cond_destroy销毁条件变量。

2. 示例:生产者-消费者模型

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>#define BUFFER_SIZE 5int buffer[BUFFER_SIZE];
int count = 0;
pthread_mutex_t lock;
pthread_cond_t not_empty;
pthread_cond_t not_full;void* producer(void* arg) {int item = 0;while (1) {pthread_mutex_lock(&lock);while (count == BUFFER_SIZE) {pthread_cond_wait(&not_full, &lock); // 缓冲区满时等待}buffer[count++] = item++;printf("Produced %d, count = %d\n", item, count);pthread_cond_signal(&not_empty); // 通知消费者pthread_mutex_unlock(&lock);usleep(100000); // 模拟生产耗时}return NULL;
}void* consumer(void* arg) {while (1) {pthread_mutex_lock(&lock);while (count == 0) {pthread_cond_wait(&not_empty, &lock); // 缓冲区空时等待}int item = buffer[--count];printf("Consumed %d, count = %d\n", item, count);pthread_cond_signal(&not_full); // 通知生产者pthread_mutex_unlock(&lock);usleep(150000); // 模拟消费耗时}return NULL;
}int main() {pthread_t p, c;pthread_mutex_init(&lock, NULL);pthread_cond_init(&not_empty, NULL);pthread_cond_init(&not_full, NULL);pthread_create(&p, NULL, producer, NULL);pthread_create(&c, NULL, consumer, NULL);pthread_join(p, NULL);pthread_join(c, NULL);pthread_mutex_destroy(&lock);pthread_cond_destroy(&not_empty);pthread_cond_destroy(&not_full);return 0;
}

3. 注意事项

  • 条件变量必须与互斥锁配合使用
    • pthread_cond_wait 会自动释放锁,等待时阻塞。
    • 被唤醒后重新获取锁,继续执行。
  • 虚假唤醒(Spurious Wakeup)
    • 线程可能在未收到信号时被唤醒,需使用 while 循环检查条件。
  • 广播 vs 信号
    • pthread_cond_broadcast 适用于“多消费者”场景,避免遗漏唤醒。

四、互斥锁与条件变量的区别

特性互斥锁(Mutex)条件变量(Condition Variable)
作用保护共享资源的独占访问协调线程间的等待与唤醒
使用方式加锁/解锁操作等待/信号操作(需配合互斥锁)
典型场景防止竞态条件等待特定条件成立(如缓冲区非空)
错误处理检查加锁失败(如死锁)检查等待失败(如中断)

五、常见问题与解决方案

1. 死锁问题

  • 原因
    • 多个线程以不同顺序加锁。
    • 线程持有锁等待另一个锁。
  • 解决方案
    • 固定加锁顺序:所有线程按统一顺序获取锁。
    • 超时机制:使用 pthread_mutex_trylock 尝试加锁,避免无限等待。

2. 条件变量未唤醒

  • 原因
    • 生产者未调用 pthread_cond_signal
    • 消费者未进入等待状态。
  • 解决方案
    • 确保在修改条件后调用 signal 或 broadcast
    • 使用调试工具(如 gdb)检查线程状态。

六、总结

  • 互斥锁(Mutex) 是解决竞态条件的基础工具,通过加锁/解锁保护共享资源。
  • 条件变量(Condition Variable) 用于协调线程间的等待与唤醒,需配合互斥锁使用。
  • 生产者-消费者模型 是条件变量的经典应用场景,通过缓冲区管理实现高效协作。
  • 注意事项
    • 避免死锁,确保加锁顺序一致。
    • 处理虚假唤醒,使用 while 循环检查条件。
    • 错误处理:检查所有同步函数的返回值。
http://www.dtcms.com/a/276564.html

相关文章:

  • 猿人学js逆向比赛第一届第二十题
  • 关于赛灵思的petalinux zynqmp.dtsi文件的理解
  • 二叉树算法进阶
  • 《Spring 中上下文传递的那些事儿》Part 8:构建统一上下文框架设计与实现(实战篇)
  • 深入理解设计模式之工厂模式:创建对象的艺术
  • Pandas 模块之数据的读取
  • 暑期前端训练day6
  • 【人工智能99问】开篇!
  • 【leetcode】1757. 可回收且低脂的产品
  • FastAdmin项目开发三
  • Python数据容器-集合set
  • 什么是 Bootloader?怎么把它移植到 STM32 上?
  • 关于两种网络攻击方式XSS和CSRF
  • 车载操作系统 --- Linux实时化与硬实时RTOS综述
  • 格密码--数学基础--06对偶空间与对偶格
  • 建造者模式(Builder)
  • Python 实战:构建可扩展的命令行插件引擎
  • Java 方法重载与构造器
  • 【Python练习】039. 编写一个函数,反转一个单链表
  • CSP-S 模拟赛 10
  • pytest自动化测试框架实战
  • 【王树森推荐系统】行为序列01:用户历史行为序列建模
  • Java责任链模式实现方式与测试方法
  • Python爬虫实战:研究xlwt 和 xlrd 库相关技术
  • 【理念●体系】迁移复现篇:打造可复制、可复原的 AI 项目开发环境k
  • 笔试题库 | 亿纬锂能社招大易笔试测评题库考点分析及真题整理
  • 张量拼接操作
  • 【IT-Infra】从ITIL到CMDB,配置管理,资产管理,物理机与设备管理(含Infra系列说明)
  • QML与C++相互调用函数并获得返回值
  • 2025 年 4-6 月大模型备案情况分析