锁和原子操作CAS的底层实现

简介: 锁和原子操作CAS的底层实现

案例:

       买火车票时,有个座位号,第几排第几个座,一排五个座位,买一个座位少一个座位,通过count++%5觉得了买的票在第几个座位,count++/5决定了在第几排;假设开十个线程;

       通过如下代码创建线程:    

在linux内核中没有进程线程之分,统一叫做task_struct,当调用pthread_create函数时,创建task_struct,创建这个结构体后的状态是new,就绪,等待,执行,退出都是线程的状态;new这个状态是还没有运行的,将其加入到队列中,这个new状态和就绪状态是一样的状态;什么时候调度是由调度器本身所决定的,不是由我们所决定的;pthread_create函数执行后什么时候运行创建的线程是不确定的,线程创建后就加入到了就绪队列中等待着被执行;  当调度器发现创建的func线程没有被执行过的时候,这个线程从new状态开始被回调,并传入count参数;调用pthread_join等待对应线程执行完返回pthread_join再往下执行,pthread_join函数是条件等待;

当有多个线程时对count++时对应的汇编代码,会出现线程1的汇编代码没有执行完,线程2就接着执行的情况;

如何解决上述问题呢?

1、互斥锁ptread_mutex_t,可以干其他事情,获得锁再执行;

2、自旋锁pthread_spinlock_t,不会干其他事情,死等直到获得锁再执行;

3、原子操作 ,即能用一条指令执行不可分割;将count++分割成汇编代码封装到inc函数中,成为不可分割的整体,如下汇编代码;

互斥锁和自旋锁和原子操作在这种场景下哪种更好;原子操作最快,所用时间最短;

下图CAS即比较后赋值,单例模式中使用这种方式实现原子操作’

原子操作的经典几个如add,sub,inc,dec,cas;

4、cpu亲缘性

       如何更加高效的利用cpu,比如有4核cpu,我们应该创建多少个线程;我们可以创建4个线程分别绑定到绑定到每个cpu上面;操作系统提供了固定的做法;

       通过cpu_set_t做粘合,比如4个cpu,进程或线程需要绑定哪个cpu,就将cpu_set_t对应位设置为1;绑定后进程或线程就只在对应cpu上运行;

上面代码中,cpu_set_t设置cpu组,这里时4个cpu,然后通过CPU_ZERO把mask清空,然后对进程self_id取模并使用这个值对mask对应位置1;然后通过sched_setaffinity对进程和cpu做粘合;粘合和进程就会只在对应cpu上运行;两个进程可以绑定在一个cpu上面;当一个进程有多个线程时,绑定的是主线程,子线程得通过子线程id去绑定cpu;

5、shmem,共享内存的做法;

       一个大文件,如何快速的读到内存中;把文件通过mmap映射到内存中,然后开启多个线程去读数据;

       mmap为什么快?磁盘的数据读到内存中通常通过cpu参与一一执行;而mmap映射是通过dma的方式,当我们一开始数据就已经到内存中了;dma是磁盘和内存间数据传输的一种方式,cpu不用参与;我们所说的零拷贝,是cpu不参与;mmap是实现共享内存的一种方式;

       可通过shm一系列接口实现映射内存;对应nginx代码如下

目录
相关文章
|
4月前
|
存储 SQL Cloud Native
热烈祝贺 Flink 2.0 存算分离入选 VLDB 2025
Apache Flink 2.0架构实现重大突破,论文《Disaggregated State Management in Apache Flink® 2.0》被VLDB 2025收录。该研究提出解耦式状态管理架构,通过异步执行框架与全新存储引擎ForSt,实现状态与计算分离,显著提升扩展性、容错能力与资源效率,推动Flink向云原生演进,开启流计算新时代。
697 1
热烈祝贺 Flink 2.0 存算分离入选 VLDB 2025
|
8月前
|
存储 关系型数据库 MySQL
携程面试:100 亿分库分表 如何设计? 核弹级 16字真经, 让面试官彻底 “沦陷”,当场发offer!
携程面试:100 亿分库分表 如何设计? 核弹级 16字真经, 让面试官彻底 “沦陷”,当场发offer!
携程面试:100 亿分库分表 如何设计?  核弹级 16字真经, 让面试官彻底 “沦陷”,当场发offer!
|
网络协议 编译器 Linux
【C语言】结构体内存对齐:热门面试话题
【C语言】结构体内存对齐:热门面试话题
432 0
|
12月前
|
开发者
在代码维护中,Qwen-coder可以通过多种方式提升编程效率和代码质量
Qwen-coder在代码维护中发挥着重要作用,帮助开发者提高代码质量,减少错误,提升开发效率。这些功能使得Qwen-coder成为代码维护和开发过程中的有力助手。
467 52
|
存储 Kubernetes 安全
云上攻防-云原生篇&K8s安全&Config泄漏&Etcd存储&Dashboard鉴权&Proxy暴露
云上攻防-云原生篇&K8s安全&Config泄漏&Etcd存储&Dashboard鉴权&Proxy暴露
420 5
|
机器学习/深度学习 人工智能 自然语言处理
【人工智能技术专题】「入门到精通系列教程」零基础带你进军人工智能领域的全流程技术体系和实战指南(LLM、AGI和AIGC都是什么)(一)
【人工智能技术专题】「入门到精通系列教程」零基础带你进军人工智能领域的全流程技术体系和实战指南(LLM、AGI和AIGC都是什么)
923 0
用户态和内核态是如何切换的?
【10月更文挑战第28天】用户态和内核态的切换是通过系统调用指令、异常和中断等机制来实现的。这些机制确保了应用程序能够在需要时请求内核提供的服务,同时也保证了内核能够对系统资源进行有效的管理和保护,维护系统的稳定性和安全性。通过准确地保存和恢复上下文信息,实现了用户态和内核态之间的无缝切换,为计算机系统的正常运行提供了有力保障。
|
安全 算法 Java
可重入锁,不可重入锁,死锁的多种情况,以及产生的原因,如何解决,synchronized采用的锁策略(渣女圣经)自适应的底层,锁清除,锁粗化,CAS的部分应用
可重入锁,不可重入锁,死锁的多种情况,以及产生的原因,如何解决,synchronized采用的锁策略(渣女圣经)自适应的底层,锁清除,锁粗化,CAS的部分应用
|
设计模式 算法 数据库连接
后端开发中的设计模式应用与实践
在软件开发的广袤天地中,设计模式如同夜空中最亮的星辰,引领着开发者们穿越复杂系统的迷雾。本文旨在通过深入浅出的方式,不仅探讨设计模式的理论精髓,揭示它们在后端架构中的重要性,还将以生动的实践案例,展示如何在实际项目中巧妙运用这些模式。我们邀请您一同踏上这场编程之旅,探索如何借助设计模式的力量,让后端系统更加健壮、灵活且易于维护,共同揭开后端技术神秘面纱的一角。
|
存储 缓存 编译器
C++11及上的原子操作底层原理与锁实现
C++11及上的原子操作底层原理与锁实现
886 0