尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

Linux线程3.0-线程同步与互斥,C/C++互斥锁。

Linux线程3.0-线程同步与互斥,C/C++互斥锁。
📅 发布时间:2026/6/24 5:40:27
@bit::Shadow
✧(≖ ◡ ≖✿

目录

原子 / 非原子

@原子操作对信号怎么处理?

非原子操作的矛盾

互斥锁

解决的问题

锁的本质

接口

定义锁

全局定义

局部定义

释放

加锁、解锁

@为什么加锁解锁都是原子的呢?

@加锁之后临界区内线程切换会怎么样?

多线程模拟并发

视频演示无锁将票抢到负数

视频演示有锁正常抢票

互斥锁的理解

执行流程

C++下的锁

互斥锁

RAII锁最常用的锁99%


原子 / 非原子

以 " a-- " 为例,探究原子与非原子。

原子操作的本质:给CPU发出指令对于“a”的修改不允许任何外部事件打断,也不允许被其他核心看到中间状态。

@原子操作对信号怎么处理?

以原子操作为优先,信号先被挂起。// kill -9 [pid]等硬核信号除外。

非原子操作的矛盾

以a--为例:

  1. 读取(Load):CPU 将a的值(3)从主内存加载到它内部的寄存器(如eax)中。

  2. 修改(Modify):CPU 在寄存器中执行eax = eax - 1,此时eax的值变为 2。

  3. 写入(Store):CPU 将寄存器中的新值(2)写回主内存中a所在的内存地址。

在以上非原子操作中,若出现并发问题那么执行流就可能发生混乱而造成预料之外的结果。

解决方法——创建互斥锁来限制线程的并发

互斥锁

解决的问题

  • 轻量级进程间信息过于同步而导致同时访问的问题。
  • 多线程下临界区内非原子性操作带来的执行流内指令重置混乱的问题。

锁的本质

☆互斥锁lock()的本质是,将原先并行的轻量级进程改为串行。

接口

pthread_mutex_t

p:POSIX(portable Operating Systemd interface)可移植操作系统接口。

mutex:(mutual exclusion)互斥。

t:(type)类型。

定义锁

锁既需要定义还需要释放

全局定义

互斥锁在全局进行定义初始化

pthread_mutex_t mutex = PTHREAD_MUTEX_INITLIZER;
局部定义

必须使用pthread_mutex_init()

pthread_mutex_t mutex; int pthread_mutex_init(pthread_mutex_t* mutex, const pthread_mutexattr_t* attr);
  1. *mutex:&锁。
  2. *attr:锁的属性,nullptr即可。

释放

int pthread_mutex_destroy(pthread_mutex_t* mutex);

加锁、解锁

不论加锁还是解锁均是原子的

phtread_mutex_lock(pthread_mutex_t* mutex); phtread_mutex_unlock(pthread_mutex_t* mutex);

加锁失败会阻塞挂起执行流。

@为什么加锁解锁都是原子的呢?

“上锁”的目的就是“保证锁内区域所有操作均是‘原子’的”,而只有持锁线程完毕才能“放下锁”——下一线程持锁进入锁区。若加锁不是原子的,那么也就导致了“持锁时并发混乱问题”。

@加锁之后临界区内线程切换会怎么样?

线程主导更换,但持锁线程不变。

多线程模拟并发

3个线程同时抢票

#include<unistd.h> #include<iostream> #include<pthread.h> static int ticket = 10000; void* routine(void* arg) { while (ticket) { //等待一会儿确保多个线程进来 usleep(500);//500ms printf("%d\n", --ticket); } return arg; } int main() { //3个新线程抢1000票 pthread_t pd1,pd2,pd3; pthread_create(&pd1, nullptr, routine, (void*)"pthread_1"); pthread_create(&pd2, nullptr, routine, (void*)"pthread_2"); pthread_create(&pd3, nullptr, routine, (void*)"pthread_3"); pthread_join(pd1, nullptr); pthread_join(pd2, nullptr); pthread_join(pd3, nullptr); return 0; }

视频演示无锁将票抢到负数

无锁多线程抢票

发现循环一直进行不会终止。

原因分析🔍

while(ticket)仅当0时判断为假usleep(500)下足够线程进入循环内会将票数直接减为负数后再出循环判断。

在原子操作区加互斥锁即可

static int ticket = 500; pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; void* routine(void* arg) { while (ticket) { pthread_mutex_lock(&mutex); if(ticket == 0) { //先前线程已然将票抢完 这些线程就解锁并退出 pthread_mutex_unlock(&mutex); break; } //等待一会儿确保多个线程进来 usleep(1000);//500ms printf("%d\n", --ticket); if(ticket == 0) pthread_mutex_unlock(&mutex); pthread_mutex_unlock(&mutex);// ticket>0解锁其他线程进来 } return arg; }

视频演示有锁正常抢票

加锁抢票

互斥锁的理解

锁限制了“原子性”标志的掌握者,下图中%al是寄存器的一种。

执行流程

1.将寄存器内数据置零。
2.交换寄存器内数据与内存。
3.根据持锁(内存中的1标志),情况决定线程行为。

C++下的锁

互斥锁

最基础的独占锁,只有一个线程可以占用。

//定义 std::mutex mutex; //加锁、解锁 mutex.lock(); mutex.unlock();

RAII锁最常用的锁99%

⚛️使用RAII原则“资源获取即初始化”,构造时自动加锁,出作用域自动解锁。(本质是封装以上述C接口的类,以调用相应的构造函数、析构函数)

std::lock_guard<std::mutex>(mtx);

由于lock_guard是作用域相关所以常常需要{}来限定。

感谢支持,持续更新
欢迎关注

相关新闻

  • 鸿蒙PC适配llvm-gcc-compat编译安装第三方库itertools,打造Rust 第三方迭代器增强库
  • 【收藏夹必备】写博文还在用“●“做列表?这些图标让文章质感翻倍!
  • 从“会聊天“到“能干活“:用 OpenCode 给自己找个 AI 搭子

最新新闻

  • Excel单元格底层数据提取:Cell2Underlying工具实现与原理详解
  • [LeetCode] 322、零钱兑换
  • AI Coding最佳实践:从RAG失效到OpenSpec可执行规范
  • 数据库小技能:资金调节活动数据报表(基于交易流水表和活动流水表)
  • MATLAB Timetable实战:列车时刻表数据分析与可视化
  • MPC8308处理器DUART与eSDHC接口详解及硬件设计要点

日新闻

  • 终极指南:如何用shadPS4在电脑上免费畅玩PS4游戏
  • 打造个性化Instagram Clone:主题定制与用户体验优化技巧
  • 未来展望:RoseTTAFold-All-Atom的发展路线图与社区支持资源汇总

周新闻

  • Visual C++运行库修复终极指南:5分钟快速解决Windows软件启动错误
  • 手把手教你构建统计局地区经济数据爬虫:从环境搭建到数据持久化全指南
  • 2026多Agent深度解析:用AI团队替代单一模型,四种架构实战落地

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号