C++并发实战19:lock free编程
发布时间 - 2025-07-20 00:00:00 点击率:次大家好,又见面了,我是你们的朋友全栈君。涉及到并行/并发计算时,通常都会想到使用锁来保护共享的数据,但锁的使用也存在一些问题:
- 效率降低:由于临界区无法并发运行,进入临界区需要等待,锁的使用导致效率下降。多核CPU也无法充分发挥其性能。
- 死锁风险:在复杂的情况下,很容易造成死锁,导致并发进程或线程之间无止境地互相等待。
- 中断/信号处理函数中的限制:在中断或信号处理函数中不能使用锁,这给并发处理带来了困难。
- 影响实时性:锁会影响实时性,等待时间不确定。
- 优先级反转:高优先级的线程可能需要等待低优先级的线程。
- 线程挂起问题:如果一个线程在持有锁的情况下挂起,会影响其他等待该锁的线程。
总之,在基于锁的多线程/多进程编程中,你需要确保对竞争条件敏感的共享数据上的任何操作,都通过加锁或解锁一个互斥锁(mutex)来实现原子操作。
现有的加锁和无锁编程的种类如下:
其中,标注为红色字体的方案为Blocking synchronization(需要锁),黑色字体的为Non-blocking synchronization(无锁)。Lock-based和Lockless-based两者之间的区别仅仅是加锁粒度的不同。图中最底层的方案就是大家经常使用的mutex和semaphore等方案,代码复杂度低,但运行效率也最低。
可以使用std::atomic来实现lock free编程,但这里并不是真正的无锁,只有atomic_flag是无锁的,其他atomic内部都是有锁的,只不过粒度很小。atomic::compare_exchange_weak/strong等同于CAS(比较并交换)操作,在C++11之前该操作是平台相关的,现在atomic将其实现为成员函数。
下面是一个lock free的栈的示例:
#include #includetemplate
class lock_free_stack // 栈的底层数据结构采用单向链表实现 { private: struct node { std::shared_ptr data; // 这里采用sharedptr管理的好处在于:若栈内存放对象,pop中return栈顶对象可能拷贝异常,栈内只存储指针还可以提高性能 node* next; node(T const& data) : data(std::makeshared (data )) // 注意make_shared比直接shared_ptr构造的内存开销小 {} }; std::atomichead; // 采用原子类型管理栈顶元素,主要利用atomic::compare_exchange_weak实现lock free public: void push(T const& data) { node* const new_node = new node(data); new_node->next = head.load(); // 每次从链表头插入 while (!head.compare_exchange_weak(new_node->next, new_node)); // 若head==new_node->next则更新head为new_node,返回true结束循环,插入成功;若head!=new_node->next表明有其它线程在此期间对head操作了,将new_node->next更新为新的head,返回false,继续进入下一次while循环。这里采用atomic::compare_exc
hange_weak比atomic::compare_exchange_strong快,因为compare_exchange_weak可能在元素相等的时候返回false所以适合在循环中,而atomic::compare_exchange_strong保证了比较的正确性,不适合用于循环 }
std::shared_ptrzuojiankuohaophpcnTyoujiankuohaophpcn pop() { node* old_head = head.load(); // 拿住栈顶元素,但是可能后续被更新,更新发生在head!=old_head时 while (old_head && !head.compare_exchange_weak(old_head, old_head-youjiankuohaophpcnnext)); // 这里注意首先要先判断old_head是否为nullptr防止操作空链表,然后按照compare_exchange_weak语义更新链表头结点。若head==old_head则更新head为old_head-youjiankuohaophpcnnext并返回true,结束循环,删除栈顶元素成功;若head!=old_head表明在此期间有其它线程操作了head,因此更新old_head为新的head,返回false进入下一轮循环,直至删除成功。 return old_head ? old_head-youjiankuohaophpcndata : std::shared_ptrzuojiankuohaophpcnTyoujiankuohaophpcn(); // 这里注意空链表时返回的是一个空的shared_ptr对象 } // 这里只是lock free,由于while循环可能无限期循环不能在有限步骤内完成,故不是wait free};
发布者:全栈程序员栈长,转载请注明出处:https://www./link/46c6a6c72edf42b1335217a9eb4b2325 原文链接:https://www./link/c8377ad2a50fb65de28b11cfc628d75c
# ai # c++ # 区别 # 无锁 # red # 有锁 # html # 成员函数 # 栈 # 线程 # 多线程 # 并发 # https # 死锁 # 链表 # 在此 # 加锁 # 能在 # 作了 # 多核 # 来实现 # 则更 # 挂起
相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571 】
相关推荐: PHP的CURL方法curl_setopt()函数案例介绍(抓取网页,POST数据) 简历在线制作网站免费版,如何创建个人简历? Laravel如何配置中间件Middleware_Laravel自定义中间件拦截请求与权限校验【步骤】 标题:Vue + Vuex 项目中正确使用 JWT 进行身份认证的实践指南 Python进程池调度策略_任务分发说明【指导】 黑客入侵网站服务器的常见手法有哪些? Laravel请求验证怎么写_Laravel Validator自定义表单验证规则教程 edge浏览器无法安装扩展 edge浏览器插件安装失败【解决方法】 JS中页面与页面之间超链接跳转中文乱码问题的解决办法 深入理解Android中的xmlns:tools属性 香港服务器如何优化才能显著提升网站加载速度? 实现点击下箭头变上箭头来回切换的两种方法【推荐】 极客网站有哪些,DoNews、36氪、爱范儿、虎嗅、雷锋网、极客公园这些互联网媒体网站有什么差异? Laravel怎么使用artisan命令缓存配置和视图 如何在七牛云存储上搭建网站并设置自定义域名? Laravel怎么实现模型属性转换Casting_Laravel自动将JSON字段转为数组【技巧】 香港服务器租用每月最低只需15元? 网站制作软件免费下载安装,有哪些免费下载的软件网站? 高端建站如何打造兼具美学与转化的品牌官网? 西安专业网站制作公司有哪些,陕西省建行官方网站? Laravel怎么实现支付功能_Laravel集成支付宝微信支付 Laravel怎么设置路由分组Prefix_Laravel多级路由嵌套与命名空间隔离【步骤】 Laravel怎么实现模型属性的自动加密 如何制作一个表白网站视频,关于勇敢表白的小标题? Gemini手机端怎么发图片_Gemini手机端发图方法【步骤】 HTML5段落标签p和br怎么选_文本排版常用标签对比【解答】 Android GridView 滑动条设置一直显示状态(推荐) html5的keygen标签为什么废弃_替代方案说明【解答】 HTML5空格和nbsp有啥关系_nbsp的作用及使用场景【说明】 Laravel怎么实现API接口鉴权_Laravel Sanctum令牌生成与请求验证【教程】 悟空浏览器如何设置小说背景色_悟空浏览器背景色设置【方法】 企业在线网站设计制作流程,想建设一个属于自己的企业网站,该如何去做? Laravel的.env文件有什么用_Laravel环境变量配置与管理详解 如何在HTML表单中获取用户输入并用JavaScript动态控制复利计算循环 Laravel怎么使用Markdown渲染文档_Laravel将Markdown内容转HTML页面展示【实战】 详解Android——蓝牙技术 带你实现终端间数据传输 如何在阿里云部署织梦网站? Midjourney怎样加参数调细节_Midjourney参数调整技巧【指南】 如何快速搭建高效服务器建站系统? Laravel如何生成和使用数据填充?(Seeder和Factory示例) java获取注册ip实例 油猴 教程,油猴搜脚本为什么会网页无法显示? Laravel如何发送系统通知?(Notification渠道示例) 如何在Windows 2008云服务器安全搭建网站? Android Socket接口实现即时通讯实例代码 详解免费开源的.NET多类型文件解压缩组件SharpZipLib(.NET组件介绍之七) Laravel项目如何进行性能优化_Laravel应用性能分析与优化技巧大全 Laravel怎么使用Intervention Image库处理图片上传和缩放 如何在Windows服务器上快速搭建网站? 如何在阿里云虚拟服务器快速搭建网站?


hange_weak比atomic::compare_exchange_strong快,因为compare_exchange_weak可能在元素相等的时候返回false所以适合在循环中,而atomic::compare_exchange_strong保证了比较的正确性,不适合用于循环
}