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

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

@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是作用域相关所以常常需要{}来限定。

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

http://www.cnnetsun.cn/news/2996195.html

相关文章:

  • 大模型微调灾难性遗忘2026:LoRA+SFT+DPO联合缓解的工程方案
  • 增量量距离保护:破解IBR电网继电保护难题的核心技术
  • Spring AI Agent Skills 工程化实践:解耦、契约与可插拔
  • 4sapi工作流引擎:2026生产级Agent的确定性架构实践
  • Vibe Coding:从指令编程到意图驱动的开发范式革命
  • DESIGN.md:从静态文档到可执行契约的工程实践
  • Spring AI Alibaba:Java企业级大模型集成的基础设施协议
  • Vue3+Vite性能优化实战:构建、响应式与加载链路闭环
  • Python3安装后command not found的根因与解决方案
  • Python3环境搭建的底层原理与四条技术路径
  • Burp Suite实战指南:从入门到精通的Web安全测试工具系统学习
  • AI生成代码如何安全落地:工程化落地流水线实践
  • 自动驾驶感知系统实战:多传感器融合与BEV+Occupancy落地
  • vLLM私有部署100倍性能提升的工程实践
  • 截断扩散模型在端到端自动驾驶规划中的工程落地
  • 彻底解决Appium iOS自动化测试WebDriverAgent启动失败Code 65错误
  • Frida在Windows逆向工程中的实战应用:动态插桩与自动化破解
  • 打破功能边界,广凌智慧教学融合平台解决方案实现全场景一体化覆盖
  • 如何获取加密货币的历史K线数据用于回测策略
  • 大模型降本实战:如何利用缓存引擎干掉50%-80%的Token消耗?(附锋范科技API调用示例)
  • GitHub中文界面终极指南:5分钟告别英文困扰,轻松掌握代码管理
  • 高校建设人工智能实验室,到底该如何选择服务商?
  • 王牌操盘手怎么样?一文看懂其运营方法论与行业价值
  • 智能体爆发前夜,为什么说底层平台才是真正的胜负手?
  • 3秒搞定图片格式转换:Chrome扩展神器Save Image as Type使用指南
  • dfs代码问题根源分析
  • TikTok国际版下载避坑指南:2026年最新完整教程
  • 独立产品从0到1:技术人的产品打磨方法论
  • 【共创季稿事节】动图魔方技术拆解 03:HarmonyOS 6.1 本地优先 GIF 工具:素材选择、文件 URI、相册保存与系统分享
  • 狼享Lite版(LAN Share Lite) 教程