锁(Mutex)、信号量(Semaphore)与条件量(Condition Variable)


一、同步机制的核心意义

在多线程/多进程编程中,当多个执行流共享资源(如变量、内存、文件)时,可能因操作顺序不确定导致数据竞争(Data Race)。同步机制的作用是:

  1. 保证原子性:确保关键代码段(Critical Section)的独占访问。
  2. 协调执行顺序:控制线程/进程的执行顺序(如生产者-消费者模型)。

二、锁(Mutex)

1. 基本概念
  • 互斥锁(Mutex):最简单的同步工具,确保同一时间只有一个线程访问共享资源。
  • 特性:锁被占用时,其他尝试获取锁的线程会被阻塞,直到锁被释放。
2. 使用步骤
  1. 初始化锁
  2. 进入临界区前加锁
  3. 退出临界区后解锁
  4. 销毁锁
3. 示例:多线程计数器
#include <pthread.h>
#include <stdio.h>int counter = 0;
pthread_mutex_t lock; // 定义互斥锁void* increment(void* arg) {for (int i = 0; i < 100000; i++) {pthread_mutex_lock(&lock); // 加锁counter++;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 counter: %d\n", counter); // 正确输出 200000pthread_mutex_destroy(&lock); // 销毁锁return 0;
}

关键点:若不加锁,counter++(非原子操作)会导致结果错误。


三、信号量(Semaphore)

1. 基本概念
  • 信号量:一种更通用的同步工具,可以控制多个线程对资源的访问。
  • 类型
    • 二进制信号量:取值0或1,功能类似锁。
    • 计数信号量:允许指定数量的线程同时访问资源。
2. 使用场景
  • 限制资源并发访问数(如数据库连接池)。
  • 生产者-消费者模型(缓冲区大小控制)。
3. 示例:生产者-消费者模型
#include <semaphore.h>
#include <pthread.h>
#define BUFFER_SIZE 5int buffer[BUFFER_SIZE];
sem_t empty, full; // 定义信号量
int in = 0, out = 0;void* producer(void* arg) {for (int i = 0; i < 10; i++) {sem_wait(&empty); // 等待空位(empty-1)buffer[in] = i;in = (in + 1) % BUFFER_SIZE;sem_post(&full); // 通知有数据(full+1)}return NULL;
}void* consumer(void* arg) {for (int i = 0; i < 10; i++) {sem_wait(&full); // 等待数据(full-1)printf("Consumed: %d\n", buffer[out]);out = (out + 1) % BUFFER_SIZE;sem_post(&empty); // 释放空位(empty+1)}return NULL;
}int main() {sem_init(&empty, 0, BUFFER_SIZE); // 初始空位数量=5sem_init(&full, 0, 0);            // 初始数据数量=0pthread_t p, c;pthread_create(&p, NULL, producer, NULL);pthread_create(&c, NULL, consumer, NULL);pthread_join(p, NULL);pthread_join(c, NULL);sem_destroy(&empty);sem_destroy(&full);return 0;
}

关键点:通过 emptyfull 信号量协调生产者和消费者的执行顺序。


四、条件变量(Condition Variable)

1. 基本概念
  • 条件变量:允许线程在某个条件不满足时主动阻塞,并在条件满足时被唤醒。
  • 必须与互斥锁配合使用:确保检查和修改条件的原子性。
2. 使用场景
  • 等待特定条件(如任务队列非空)。
  • 避免忙等待(Busy Waiting),节省CPU资源。
3. 示例:任务队列调度
#include <pthread.h>
#include <stdbool.h>pthread_mutex_t lock;
pthread_cond_t cond;   // 条件变量
bool task_available = false;void* worker(void* arg) {pthread_mutex_lock(&lock);while (!task_available) {pthread_cond_wait(&cond, &lock); // 阻塞并释放锁,被唤醒后自动重新加锁}printf("Processing task...\n");task_available = false;pthread_mutex_unlock(&lock);return NULL;
}void* scheduler(void* arg) {pthread_mutex_lock(&lock);task_available = true;pthread_cond_signal(&cond); // 唤醒等待的线程pthread_mutex_unlock(&lock);return NULL;
}int main() {pthread_t t_worker, t_scheduler;pthread_mutex_init(&lock, NULL);pthread_cond_init(&cond, NULL);pthread_create(&t_worker, NULL, worker, NULL);sleep(1); // 确保worker先进入等待pthread_create(&t_scheduler, NULL, scheduler, NULL);pthread_join(t_worker, NULL);pthread_join(t_scheduler, NULL);pthread_mutex_destroy(&lock);pthread_cond_destroy(&cond);return 0;
}

关键点

  • pthread_cond_wait原子性地释放锁并阻塞线程,被唤醒后重新获取锁。
  • 必须使用 while 检查条件(避免虚假唤醒)。

五、三者的对比与选择

机制用途特点
保护临界区,确保独占访问简单、轻量,仅支持互斥
信号量控制资源访问数量或协调执行顺序灵活,支持计数和复杂同步逻辑
条件变量等待特定条件成立需与锁配合,避免忙等待

选择原则

  • 简单互斥 → 锁。
  • 控制资源数量 → 信号量。
  • 等待条件成立 → 条件变量。

六、深入:常见问题与陷阱

  1. 死锁

    • 场景:多个锁未按顺序获取。
    • 解决:统一加锁顺序,或使用超时机制(如 pthread_mutex_trylock)。
  2. 优先级反转

    • 场景:低优先级线程持有高优先级线程需要的锁。
    • 解决:优先级继承(如 pthread_mutexattr_setprotocol)。
  3. 虚假唤醒

    • 场景:pthread_cond_wait 可能无故返回。
    • 解决:始终在 while 循环中检查条件。

通过合理使用锁、信号量和条件变量,可以构建高效且安全的并发程序。实际开发中需严格测试同步逻辑。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/77371.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

前端基础之《Vue(6)—组件基础(2)》

接上一篇。 七、v-model深入学习 <html> <head><title>组件基础-4</title><style>.score {display: inline-block;}.score>span {display: inline-block;width: 25px;height: 25px;background: url(./assets/star.png) center center / 25p…

SQL:聚合函数(Aggregate Functions)

目录 第一性原理出发思考 ——我们为什么需要聚合函数&#xff1f; 什么是聚合函数&#xff1f; 常见聚合函数 实例讲解 &#x1f538; 1. COUNT() —— 计数 &#x1f538; 2. MAX() / MIN() —— 最大 / 最小值 &#x1f538; 3. SUM() —— 求和 &#x1f538; 4. …

海关总署广东:广东外贸一季度进出口2.14万亿元 同期增长4.2%

大湾区经济网湾区财经报道&#xff0c;据海关总署广东分署统计&#xff0c;今年一季度&#xff0c;广东外贸进出口2.14万亿元&#xff0c;较去年同期&#xff08;下同&#xff09;增长4.2%&#xff0c;增速高于全国2.9个百分点。其中&#xff0c;出口1.34万亿元&#xff0c;增长…

MySQL中高级语法

Mysql高级语法 持续更新中… 1、EXISTS语法 一、基本语法结构 SELECT [列名] FROM [主表] WHERE [条件]AND EXISTS (SELECT 1 -- 子查询内容无关&#xff0c;仅需占位符&#xff08;如1、*、X等&#xff09;FROM [子查询表]WHERE [关联条件] -- 必须与外层查询关联&#xf…

SpringBoot 调用deepseek

个人学习心得&#xff0c;仅供参考 软件环境&#xff1a; JDK 17 你用JDK 11 无法支持SpringBoot 3SpringBoot 3 版本以上才支持spring aimavan 3.6.11.获取Deepseek官网的API-key 官网&#xff1a;https://platform.deepseek.com/api_keys 2.创建项目 这样创建 添加依赖…

性能测试面试题的详细解答

以下是性能测试面试题的详细解答&#xff1a; 1. 性能测试的流程是怎样的&#xff1f; 性能测试流程通常包括以下几个步骤&#xff1a; - **需求分析**&#xff1a;明确测试目标、性能指标&#xff08;如响应时间、吞吐量等&#xff09;。 - **环境搭建**&#xff1a;搭建测试环…

C++程序设计基础实验:C++对C的扩展特性与应用

C程序设计基础实验&#xff1a;C对C的扩展特性与应用 &#x1f525; 本文详细讲解C基础实验&#xff0c;包含C对C语言的扩充与增强特性&#xff0c;从零开始掌握函数重载、引用、指针等核心概念&#xff0c;附详细代码分析与运行结果。适合C初学者和有C语言基础想学习C的同学&a…

量子神经网络编译器开发指南:从理论突破到产业落地全景解析

本文深度剖析IBM Qiskit 5.0量子经典混合编译器的技术架构&#xff0c;详解如何基于含噪量子处理器实现MNIST手写数字分类任务&#xff08;准确率达89%&#xff09;。结合本源量子云、百度量子等国内平台免费配额政策&#xff0c;系统性阐述量子神经网络开发的技术路线与资源获…

ESP32之本地HTTP服务器OTA固件升级流程,基于VSCode环境下的ESP-IDF开发(附源码)

背景知识&#xff1a; 本实验利用编译链内Python内置的 HTTP 服务器&#xff0c;将升级包通过http发送给设备&#xff0c;实现OTA固件升级。 目录 背景知识&#xff1a; 1.创建工程 1.1 创建OTA基础工程 3.编写、修改代码 3.1 修改menuconfig配置文件 3.1.1 配置WiFi账…

BootStrap:进阶使用(其一)

今天我要讲述的是在BootStrap中进一步使用的方法与代码举例; 导航条 作为在应用或网站中作为导航页头的响应式基础组件。导航条在移动设备上可以折叠&#xff08;且可开可关&#xff09;&#xff0c;在视口&#xff08;viewport&#xff09;宽度增加时逐渐变为水平展开模式 …

ffmpeg无损转格式的命令行

将ffmpeg.exe拖入命令行窗口 c:\users\zhangsan>D:\ffmpeg-2025-03-11\bin\ffmpeg.exe -i happy.mp4 -c:v copy -c:a copy 格式转换后.mkv -c:v copy 仅做拷贝视频,不重新编码 -c:a copy 仅做拷贝音频 ,不重新编码

【Linux】深入理解Linux文件系统:从C接口到内核设计哲学

文章目录 前言一、C语言中的文件接口1. 文件指针&#xff08;句柄&#xff09;FILE*以写方式打开文件&#xff0c;若文件不存在会新建一个文件W写入方式&#xff0c;在打开文件之前都会将文件内容全部清空追加写方式&#xff0c;其用法与写方法一致&#xff0c;不同在于a方法可…

国产品牌芯洲科技100V降压芯片系列

SCT2A25采用带集成环路补偿的恒导通时间(COT)模式控制&#xff0c;大大简化了转换器的片外配置。SCT2A25具有典型的140uA低静态电流&#xff0c;采用脉冲频率调制(PFM)模式&#xff0c;它使转换器在轻载或空载条件下实现高转换效率。 芯洲科技100V降压芯片系列提供丰富的48V系…

ctfshow-大赛原题-web702

因为该题没有理解到位&#xff0c;导致看wp也一直出错&#xff0c;特此反思一下。 参考yu22x师傅的文章 &#xff1a;CTFSHOW大赛原题篇(web696-web710)_ctfshow 大赛原题-CSDN博客 首先拿到题目&#xff1a; // www.zip 下载源码 我们的思路就是包含一个css文件&#xff0c;…

LabVIEW技巧——获取文件版本信息

获取可执行文件&#xff08;exe&#xff09;版本信息的几种方法 方法1. LabVIEW自带函数 labview自带了获取文件版本号的VI&#xff0c;但是没有开放到程序框图的函数选板中&#xff0c;在该目录下可以找到&#xff1a;...\LabVIEW 20xx\vi.lib\Platform\fileVersionInfo.llb…

三格电子——CAN 转光纤(点对点)布线常见问题

1、CAN 布线 &#xff08;1&#xff09;H 接 H ,L 接 L &#xff08;2&#xff09;两端设备挂 120 欧姆电阻 2、假如用点对点的 CAN 转光纤现实远程传输 &#xff08;1&#xff09;H 接 H ,L 接 L &#xff08;2&#xff09;光端机都挂 120 欧姆电阻 每个光端机挂的设备有一个加…

python进阶: 深入了解调试利器 Pdb

Python是一种广泛使用的编程语言&#xff0c;以其简洁和可读性著称。在开发和调试过程中&#xff0c;遇到错误和问题是不可避免的。Python为此提供了一个强大的调试工具——Pdb&#xff08;Python Debugger&#xff09;。 Pdb是Python标准库中自带的调试器&#xff0c;可以帮助…

React 设计艺术:如何精确拆分组件接口,实现接口隔离原则

接口隔离原则 接口隔离原则&#xff08;Interface Segregation Principle&#xff0c;简称 ISP&#xff09;也是面向对象设计中的重要原则之一。它的核心思想是&#xff0c;一个类不应该依赖它不需要的接口。在 React 开发中&#xff0c;遵循接口隔离原则可以提高代码的可维护性…

内部聊天软件,BeeWorks-安全的企业内部通讯软件

企业在享受数据便利的同时&#xff0c;如何保障企业数据安全已经成为无法回避的重要课题。BeeWorks作为一款专为企业设计的内部通讯软件&#xff0c;通过全链路的安全能力升维&#xff0c;为企业提供了一个安全、高效、便捷的沟通协作平台&#xff0c;全面保障企业数据安全。 …

【零基础】基于 MATLAB + Gurobi + YALMIP 的优化建模与求解全流程指南

MATLAB Gurobi YALMIP 综合优化教程&#xff08;进阶&#xff09; 本教程系统介绍如何在 MATLAB 环境中使用 YALMIP 建模&#xff0c;并通过 Gurobi 求解器高效求解线性、整数及非线性优化问题。适用于工程、运营研究、能源系统等领域的高级优化建模需求。 一、工具概览 1.…