C++ 异步编程探索(二) thread safe

c++11 线程池系列之一 所需要的thread_safe_queue template class thread_safe_queue { private: mutable std::mutex mut; std::queue> data_queue; std::condition_variable data_con; public: thread_safe_queue(){} thread_safe_queue(thread_safe_queue con 阅读详情

前言

在异步编程实践中,曾经遇到的最大的问题就是thread safe 问题。

我所在的团队是Database团队,主要是为APP提供和redis交互的API。场景就是application thread调用我们的API。我们有个worker thread负责网络I/O。我们的API基于hiredis,hiredis声明自己不是thread-safe。
这也很正常,看了看hireids的代码,关于网络通信的部分,其中有个i-buffer和一个o-buffer这两个buffer负责缓存和网络通信的信息。hiredis将“poll”这部分做了抽象,可以兼容很多异步框架比如redis的ae,libevent等等。hiredis的做法是当网络可写的时候,调用send,如果send没有将o-buf发送完全时,调用eladdwrite,告诉系统,网络可写时告诉我。
那么为什么它不是线程安全的呢? 首先如果要做到线程安全,这两个buffer就需要“加锁”来防止两个线程通知操作相同的buffer,但是hiredis中没有相应的处理代码

既然hiredis没有提供线程安全的API,那么如何解决这个问题呢?

异步事件通知机制

异步编程无法避免都要面对多个线程,这个就要涉及到线程之间的通信。解决方法有很多,比如上篇文章中提到过的boost furure-then, 但是这样的缺点是每个then多会新建一个线程处理task,起线程会很耗资源。所以有人就会想,一开始就建立多个线程形成一个线程池,这样就消除了不断起线程的损耗。这确实是一个好办法,但是这也引入一个问题–如何拖住这个线程,不让线程退出。解决方法同样有很多。比如用condition wait,poll…
至此就正式引出异步事件通知机制。异步事件通知机制有很多种类,其大多数都是基于epoll kqueue等linux底层API。下面我就举几个比较著名的框架:

libevent

libevent是我最早接触的此类框架,其支持linux各种file discriptor(fd),之前写了一个小demo。link:https://github.com/maxcong001/task_base
想法就是运用libevent作为poll机制,监听eventfd。APP线程当有事情的时候就将事情push到一个queue中(加锁),同时eventfd加一,这样libeventthread就会被唤醒,看看有多少事件需要处理,并从queue中提取相应的事情并处理。

libuv

libuv和libevent相似,相比libevent更加轻量,同时实现稍有不同,同样我写了一个小的demo,link:https://github.com/maxcong001/task_base_libuv
这里libuv支持uv_async_send这样的API不用我们再去监听fd。同时这个小demo中还用的线程安全的无锁queue(以后会写有关无锁队列的文章,这里就不介绍了)。

boost::asio::io_service(io_context 新版本boost)

boost这个神器总不会让人失望,io_service抽象了底层I/O, 所有异步io事件都是通过它来分发处理的,当然也包括我们需要的异步事件通知机制,主要我们可以调用post方法, post用于发布io事件,如timer,socket读写等,一般由asio框架相应对象调用,无需我们显式调用。新版本的io_context 的post直接可以带handler。本来写了个小程序,由于种种原因不能在公司之外分享。

异步事件数据的线程安全

两个线程之间互动,不可避免的是共享一些数据结构,上一个章节,讲到libevent时,提到了一个queue,这里存着要处理的任务,由于可能有多个线程操作这个queue,为了解决这个问题,简单粗暴的加锁。

众所周知加锁是一个很耗的操作。同时等待锁也很绝望,用不好还会产生死锁
上一章节讲到libev时就升级了一下用了无锁queue
当讲到asio时候更进一步。这里我们可以使用lambda函数捕获一些数据,关于捕获,C++11以后我们会谈更多

异步事件结果的返回

对于结果的返回,有两种例子,第一种就是结果在当前线程中直接处理,第二种就是将结果传回发起task的线程

传回发起task的线程

如果两个线程都是消息驱动的, 可以发一个消息给原线程。
如果只有一个线程是消息驱动的,可以参考future.get()。当需要用某个变量时,调用get,但这可能会阻塞。

在当前线程处理

这就涉及到一个编程思想的问题。如何将一个task做到thread不感知。

C++ std::async 异步编程实战:从原理到避坑指南 异步编程是现代软件开发中提升程序响应能力的关键技术,其核心原理在于将耗时操作(如网络请求、文件读写)与主线程分离,避免界面卡顿。通过将任务提交到后台执行,程序可以立即响应用户交互,待任务完成后再处理结果,这显著提升了用户体验和系统吞吐量。在C++中,标准库提供了强大的并发工具来实现这一模式。其中,std::async作为异步操作的启动器,封装了线程创建与结果获取的复杂性,让开发者能以简洁的同步风格编写异步代码,极大地降低了并发编程的门槛。它通过返回std::future对象来承载异步结果,并支持灵活的启动策 阅读详情

相关推荐

C++异步编程三大陷阱:future析构阻塞、异常丢失与内存模型误区

异步编程是现代软件开发中提升性能与响应能力的关键技术,其核心原理在于通过非阻塞方式执行任务,避免线程等待,从而提高资源利用率。在C++中,从传统的std::future到C++20协程,标准库提供了丰富的异步工具。然而,其技术价值往往被底层复杂性和隐蔽陷阱所抵消,尤其是在高并发生产环境中。开发者常因对共享状态生命周期、异常传播机制及内存序理解不足,导致程序出现难以调试的性能下降或崩溃问题。本文聚焦于std::future的阻塞析构、异步边界异常静默丢失以及数据竞争与内存序认知误区三大核心陷阱,结合线程池与协

weixin_30785593的博客 610

vs2003-hiredis-vc++客户端连接池,线程安全

vs2003-hiredis-vc++客户端连接池,线程安全。 下载地址:http://download.youkuaiyun.com/detail/ldsmails/4078854 使用开源软件地址:http://blog.lovor.net/

ldsmails的专栏 1866

C++多线程编程实战:从std::thread到线程安全设计

并发编程是现代软件开发中提升性能的核心技术,它允许多个任务同时执行,从而充分利用多核CPU的计算能力。其基本原理是通过创建多个执行流(线程)来并行处理任务,关键技术包括线程同步、互斥锁和原子操作。在C++工程实践中,掌握多线程技术能显著提升服务端数据处理、图形界面响应等场景的性能。本文聚焦于C++11引入的std::thread库,深入解析其线程生命周期管理、数据竞争防范以及条件变量等同步机制,并结合互斥锁与RAII守卫等实战技巧,帮助开发者规避死锁、数据竞争等常见陷阱,构建高效可靠的并发程序。

weixin_30847939的博客 325

Hiredis

简介本文翻译自Hiredis官方,README.md文件。Hiredis是Redis数据库的简约C客户端库。它是简约的,因为它只是增加了对协议的 最小支持,但是同时它使用了一个高级别的printf-like API,所以对于习 惯了printf风格的C编程用户来说,其非常容易使用,而且API中没有明确的绑定 每 个Redis命令。除了支持发送命令和接收回复之外,它还附带了一个与I / O层分离

飞翔de刺猬 1万+

C++单文件HTTP库cpp-httplib:从原理到实战构建轻量级网络服务

HTTP协议作为现代网络通信的基石,其客户端与服务器实现是构建Web服务、API接口和微服务架构的核心技术。理解HTTP协议栈的工作原理,有助于开发者选择高效、易用的网络库来快速实现业务需求。在C++生态中,cpp-httplib以其独特的单文件、零外部依赖设计脱颖而出,为开发者提供了开箱即用的HTTP/HTTPS服务与客户端能力。该库基于C++11标准库,内部采用多线程同步模型与线程池管理连接,在易用性与性能间取得了良好平衡。其技术价值在于极大降低了C++项目集成网络功能的复杂度,尤其适合快速原型开发、嵌

dianyin7770的博客 529

C++20协程深度解析:从异步编程原理到Boost.Asio实战应用

协程是一种支持函数在执行过程中挂起和恢复的编程模型,它通过保存函数执行状态而非依赖传统调用栈来实现。其核心原理在于将函数执行状态存储在堆上,允许在特定点暂停并后续恢复,从而避免了线程切换的开销。这种机制的技术价值在于能够以同步的代码风格编写高效的异步逻辑,显著提升代码可读性和可维护性。在应用场景上,协程特别适合高并发服务器、游戏引擎、流处理等涉及大量I/O等待的场景。C++20协程作为语言级原语,通过`co_await`、`co_yield`、`co_return`等关键字,结合`promise_type`

weixin_34161032的博客 357

线程安全(thread-safe)介绍

要介绍“线程安全”,那么就必须要提“线程不安全”,甚至可以说,是先出现了“线程不安全”这个问题,后来为了解决这个问题,才有了“线程安全”的概念。“线程安全”和“线程不安全”的相关内容,都是在涉及多线程编程时才会用到,在单线程的场景下无需考虑。至于为何需要多线程编程,请参考此文。在操作系统中,线程是由进程创建的,线程本身几乎不占有系统资源,线程用到的系统资源是属于进程的。一个进程可以创建多个线程,这些线程共享着进程中的资源。

liitdar的博客 3706

hiredis的c++封装, 线程安全

hiredis的c++封装, 线程安全, 提供对键值对、队列、散列、集合结构的读写

终极指南:破解Hiredis多线程安全访问瓶颈,实现高并发Redis客户端最佳实践

Hiredis作为Redis官方推荐的C语言客户端库,以其轻量级设计和高效性能被广泛应用于高性能服务开发中。然而在多线程环境下,Hiredis的`redisContext`和`redisAsyncContext`对象并非线程安全,这成为许多开发者实现高并发访问时的主要障碍。本文将系统讲解Hiredis多线程安全的实现原理,提供3种经过验证的线程安全访问方案,并通过实际代码示例展示如何在生产环境中安

gitblog_00651的博客 766

VMFS数据存储(datastore)丢失后恢复步骤

vmfs datastore恢复步骤

jetliu05的博客 3267

Codex驱动AEDT完成无线充电仿真——从双线圈建模到三维电磁场动画

本文介绍了一个利用Codex、PyAEDT和Ansys Electronics Desktop 2025 R2实现双线圈无线充电系统自动建模与仿真的案例。通过简化模型(平面线圈+铁氧体磁芯),完成了从参数化建模、电磁场求解到后处理的全流程自动化,获得了耦合系数(k=0.17)、三维电磁场分布及多周期动态可视化效果。研究发现:线圈间距对传输效率影响最大(10-30mm间距时效率从40.2%降至5.57%),横向偏移15mm会使效率下降35%,而磁芯厚度增加带来的效率提升有限(3→7mm仅提高1.67%)。该框

sjjsjjsjjsjjsjj的博客 447

cpp_redis异步编程指南:如何利用C++11特性实现高性能Redis操作

cpp_redis是一个基于C++11的轻量级Redis客户端,它支持异步操作、线程安全、无依赖、管道化和跨平台特性。本指南将详细介绍如何利用cpp_redis的异步编程能力和C++11新特性来实现高性能的Redis操作,帮助开发者构建高效可靠的分布式应用。 ## 为什么选择cpp_redis进行异步Redis编程? cpp_redis作为一款现代化的C++ Redis客户端,具有以下核心优势

gitblog_00135的博客 459

【机械臂算法】基于最小惯性参数集的动力学辨识仿真实践

本文深入探讨了机械臂动力学参数辨识的核心挑战与解决方案,重点阐述了基于最小惯性参数集的理论与方法。通过分析PUMA560实例,详细介绍了利用QR分解法或符号推导法获取可辨识参数集,并系统讲解了从激励轨迹设计、仿真数据采集、线性系统求解到模型验证的完整实践流程,为高精度动力学建模与控制奠定了坚实基础。

weixin_29054399的博客 376

pdf2zh 快速上手:2 条命令翻译 PDF 论文,排版公式全保留

读外文论文,译文一翻公式就散架,手工重排又没那个劲头?把这个丢给 pdf2zh。敲两条命令,拿回一份完全保留原版式的中文 PDF,外加一份中英对照。学生读文献、研究者追论文,直接用。 ## 两条命令跑通 先说清楚:Python 得是 3.11 或 3.12,装依赖时 onnxruntime、gradio 这些会自动带入,不用手装。 ```bash pip install pdf2zh pdf

gitblog_00373的博客 747

STM32 使用IO口模拟I2C时序

上一篇《I2C协议详解》 我们了解了I2C的操作流程,这一篇,我们就使用I2C,来对EEPROM进行操作吧。 我们做两种选择: 1.时序由IO口模拟高低电平,需要了解协议并按照协议操作相应的IO口。 2.时序由硬件自行产生,不需要人工干预; 由硬件产生的I2C时序,我们借助Stm32Cube配置实现便可,我们这一篇,抛开Stm32Cube,手撕代码,根据I2C的时序,一步步地实现I2C对...

8937

【Tessent Shell Users Manual】【Ch3】Design Introspection and Editing(未完待续)

Tessent Shell 提供了一系列用于检查(examining/introspecting)和编辑design的命令。

Tranquil_ovo的博客 1731

cpp_redis源码架构解析:深入理解现代C++ Redis客户端设计模式

cpp_redis是一个基于C++11的异步多平台轻量级Redis客户端库,它支持同步操作、流水线、哨兵和高可用性。这个现代化的C++ Redis客户端库设计精巧,采用了多种现代C++设计模式,为开发者提供了高效、线程安全的Redis访问能力。本文将深入解析cpp_redis的源码架构,帮助您理解其核心设计思想和实现原理。 ## 架构概览:分层设计与模块化 cpp_redis采用了清晰的分层架

gitblog_01072的博客 1007

VOSviewer文献可视化006:修改节点标签文字

由VOSviewer软件生成的可视化图形所显示的文字是小写的,有时候,我们希望其所显示的数据(如国家或作者的首字母等)能够以大写的方式呈现,这时可以进行对节点标签文字的修改操作,使图形显示我们想要的一个效果。

qq_41725964的博客 6152

终极C++ Redis客户端cpp_redis:异步、线程安全的轻量级解决方案

cpp_redis是一个C++11异步多平台轻量级Redis客户端,支持同步操作、管道化、哨兵和高可用性。作为一款高性能的C++ Redis客户端,它无需依赖其他库,仅需C++11环境即可运行,为开发者提供了便捷且高效的Redis交互方式。 [![cpp_redis架构图](https://raw.gitcode.com/gh_mirrors/cpp/cpp_redis/raw/201d96c5

gitblog_00685的博客 266

高数15种常见特殊曲线:星形线、心形线、摆线、对数螺线、双曲螺线、阿基米德螺线、伯努利双纽线、三叶玫瑰线、四叶玫瑰线、六叶玫瑰线、三次抛物线、半立方抛物线、箕舌线、蔓叶线、笛卡儿叶形线、概率曲线

4.1 对数螺线(等角螺线、生长螺线)三叶玫瑰线、四叶玫瑰线、六叶玫瑰线。​7.2 半立方抛物线(尼尔曲线)10.笛卡儿叶形线(茉莉花瓣曲线)常考选择题、填空题,大题也涉及。​4.2 双曲螺线(倒数螺线)11.阿基米德螺线(等速螺线)3.摆线(圆滚线、旋轮线)5.双纽线(伯努利双纽线)1.星形线(四尖瓣线)2.心形线(心脏线)..................

刘鑫磊 1万+

全网详细解决Client does not support authentication protocol requested by server;consider upgrading Mysql c

全网详细解决1251 - Client does not support authentication protocol requested by server; consider upgrading Mysql client。

念兮为美 5478

cpp_redis跨平台部署指南:在Windows、Linux和macOS上的配置与优化

cpp_redis是一个基于C++11的轻量级Redis客户端库,提供异步、线程安全、无依赖、支持流水线和跨平台的Redis连接能力。作为现代C++开发的理想选择,cpp_redis让开发者能够在Windows、Linux和macOS三大主流平台上轻松集成Redis功能,无需担心平台差异带来的兼容性问题。🎯 ## 为什么选择cpp_redis进行跨平台开发? cpp_redis作为一款优秀的

gitblog_00735的博客 903

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

C++11 std::thread:从线程创建到同步原语的完整指南

并发编程是现代软件开发中提升程序性能的核心技术,它允许程序同时执行多个任务,从而充分利用多核处理器的计算能力。其基本原理是通过创建多个执行流(线程)来并行处理任务,关键技术包括线程生命周期管理、数据同步和通信机制。在C++11标准中,std::thread的引入为多线程编程带来了标准化和可移植性,它抽象了底层操作系统的线程接口,并与互斥量、条件变量等同步原语无缝集成,共同构成了安全高效的并发编程基础。这一技术价值在于显著提升了程序的响应速度和处理吞吐量,广泛应用于服务器后端的高并发处理、客户端程序的界面响应

372

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

C++17 Lambda捕获*this:解决异步编程中对象生命周期安全的核心机制

在C++编程中,Lambda表达式作为函数对象的轻量级替代,极大地简化了回调、STL算法和异步任务编写。其核心原理是通过捕获列表将外部变量或对象状态绑定到闭包内部,形成独立的执行上下文。然而,传统捕获this指针的方式存在悬垂指针风险,当对象销毁后异步任务仍在访问成员时会导致未定义行为。C++17引入的[*this]捕获机制通过值捕获整个对象副本,从根本上解决了这一安全问题,使Lambda内部拥有完全独立的对象生命周期。这一技术价值在于为高并发服务器、嵌入式系统和事件驱动架构提供了内置的线程安全保证,无需开

weixin_30553777的博客 320

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

终极指南:如何实现cpp_redis与STL Future的无缝同步异步切换

Redis作为高性能键值存储系统,在现代C++应用中扮演着重要角色。cpp_redis是一个C++11轻量级Redis客户端库,支持异步、线程安全、无依赖、管道化和多平台等特性。本文将深入探讨cpp_redis与STL Future的集成,展示如何在同步与异步操作之间实现无缝切换,为开发者提供灵活高效的Redis操作方案。😊 [![cpp_redis架构图](https://raw.gitco

gitblog_00793的博客 320

【项目】C++从零实现JsonRpc框架——项目引入

本文介绍了一个基于C++实现的简易RPC通信框架,使用JsonCpp库进行序列化/反序列化,muduo网络库处理底层通信。该框架支持同步/异步调用、服务注册发现、负载均衡等功能,通过JSON格式传输参数和返回值,使开发者无需关注网络细节即可快速实现远程调用。文章详细讲解了JsonCpp的核心类和使用方法,并简要介绍了muduo库的高性能网络架构特点。该RPC框架设计简洁高效,适合快速开发分布式系统服务。

记录我一步步的学习历程,期待无限进步,向星举目! 716
上一篇: C++ 异步编程探索(一) task链式调度 -- future CONTINUATION
下一篇: 对于线程间传递消息的一些想法 -- 智能指针+lambda caputre(封装task)
Max_Cong
博客等级 码龄10年 281粉丝 85原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值