news 2026/6/24 5:25:16

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
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是作用域相关所以常常需要{}来限定。

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/24 5:20:45

大模型微调灾难性遗忘2026:LoRA+SFT+DPO联合缓解的工程方案

背景&#xff1a;灾难性遗忘为何在2026年更棘手 灾难性遗忘&#xff08;Catastrophic Forgetting&#xff09;是神经网络微调中的经典难题&#xff1a;模型在学习新任务时会显著遗忘旧任务的能力。对大语言模型而言&#xff0c;这意味着&#xff1a;- 对中文医疗问答进行 SFT 后…

作者头像 李华
网站建设 2026/6/24 5:13:54

增量量距离保护:破解IBR电网继电保护难题的核心技术

1. 项目概述&#xff1a;当传统距离保护遇上IBR电网在电力系统继电保护领域&#xff0c;距离保护一直扮演着“线路守护神”的角色。它的核心逻辑简单而强大&#xff1a;通过测量保护安装处的电压和电流&#xff0c;计算出故障点到保护安装处的阻抗&#xff0c;并与预先设定的整…

作者头像 李华
网站建设 2026/6/24 5:05:15

Spring AI Agent Skills 工程化实践:解耦、契约与可插拔

1. 为什么“Agent Skills”不是新名词&#xff0c;而是智能体工程化的分水岭“Agent Skills”这个词最近在 Spring 生态里突然密集出现&#xff0c;尤其在 Spring AI 2.0-rc2 发布后&#xff0c;社区讨论从“怎么调用大模型 API”迅速转向“怎么让 Agent 真正干活”。但我要先泼…

作者头像 李华
网站建设 2026/6/24 5:01:50

4sapi工作流引擎:2026生产级Agent的确定性架构实践

1. 这不是又一个“Hello World”Agent Demo&#xff1a;为什么2026年必须重写工作流底层逻辑你肯定见过太多Agent演示&#xff1a;三行代码调用一个API&#xff0c;再加个“思考中…”的loading动画&#xff0c;最后吐出一句“我已为您生成会议纪要”。这种演示在2024年还能博得…

作者头像 李华
网站建设 2026/6/24 4:59:20

Vibe Coding:从指令编程到意图驱动的开发范式革命

1. “Vibe Coding”不是玄学&#xff0c;是开发者工作流的范式迁移“2025&#xff0c;我确诊了‘Vibe Coding’”——这句话在技术社区刷屏时&#xff0c;我正盯着 Cursor IDE 里自动补全的第7个函数签名发呆。它没写错&#xff0c;但也没完全写对&#xff1a;参数名用了驼峰&a…

作者头像 李华
网站建设 2026/6/24 4:57:49

DESIGN.md:从静态文档到可执行契约的工程实践

1. 这不是又一个 Markdown 编辑器&#xff0c;而是让 DESIGN.md 成为产品设计流水线的活接口你有没有遇到过这样的场景&#xff1a;团队在用 Git 管理后端服务时&#xff0c;把DESIGN.md当作接口契约、状态机定义或模块职责说明书——它不是文档&#xff0c;是代码的上游输入&a…

作者头像 李华