C++并发编程之异常安全性增强

在并发编程中,异常安全是一个非常重要的方面,因为并发环境下的错误处理比单线程环境更加复杂。当多个线程同时执行时,异常不仅可能影响当前线程,还可能影响其他线程和整个程序的稳定性。以下是一些增强并发程序异常安全性的方法,并附有示例代码。

1. 异常捕获和处理

在多线程程序中,每个线程都应该有自己的异常捕获机制。常见的做法是在每个线程的入口点(如线程函数)中使用 try-catch 块来捕获和处理异常。

示例代码:
#include <iostream>
#include <thread>
#include <exception>void threadFunction() {try {// 模拟可能抛出异常的代码throw std::runtime_error("An error occurred in the thread");} catch (const std::exception& e) {std::cerr << "Exception caught in thread: " << e.what() << std::endl;// 可以在这里进行日志记录、资源清理等操作}
}int main() {std::thread t(threadFunction);t.join();return 0;
}

2. 资源管理

使用 RAII(Resource Acquisition Is Initialization)技术来管理资源,确保资源在异常情况下也能正确释放。C++ 中的智能指针(如 std::unique_ptr 和 std::shared_ptr)和 std::lock_guard 等都是 RAII 的典型应用。

示例代码:
#include <iostream>
#include <thread>
#include <memory>
#include <mutex>std::mutex mtx;void threadFunction() {try {std::unique_ptr<int> resource(new int(42));std::lock_guard<std::mutex> lock(mtx);// 模拟可能抛出异常的代码throw std::runtime_error("An error occurred in the thread");} catch (const std::exception& e) {std::cerr << "Exception caught in thread: " << e.what() << std::endl;}
}int main() {std::thread t(threadFunction);t.join();return 0;
}

3. 线程同步

在多线程环境中,确保线程间的同步非常重要。使用互斥锁、条件变量等同步原语时,要确保在异常情况下不会导致死锁或资源泄露。

示例代码:
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>std::mutex mtx;
std::condition_variable cv;
bool ready = false;void prepare() {try {std::this_thread::sleep_for(std::chrono::milliseconds(1000));std::lock_guard<std::mutex> lock(mtx);ready = true;cv.notify_one();} catch (const std::exception& e) {std::cerr << "Exception caught in prepare: " << e.what() << std::endl;// 可以在这里进行日志记录、资源清理等操作}
}void waitAndPrint() {try {std::unique_lock<std::mutex> lock(mtx);cv.wait(lock, [] { return ready; });std::cout << "Ready is true" << std::endl;} catch (const std::exception& e) {std::cerr << "Exception caught in waitAndPrint: " << e.what() << std::endl;}
}int main() {std::thread t1(prepare);std::thread t2(waitAndPrint);t1.join();t2.join();return 0;
}

4. 异常传播

在多线程环境中,异常可能需要从一个线程传播到另一个线程。可以使用 std::promise 和 std::future 来实现异常的跨线程传播。

示例代码:
#include <iostream>
#include <thread>
#include <future>void threadFunction(std::promise<int> promise) {try {// 模拟可能抛出异常的代码throw std::runtime_error("An error occurred in the thread");promise.set_value(42);} catch (const std::exception& e) {promise.set_exception(std::current_exception());}
}int main() {std::promise<int> promise;std::future<int> future = promise.get_future();std::thread t(threadFunction, std::move(promise));t.join();try {int value = future.get();std::cout << "Value: " << value << std::endl;} catch (const std::exception& e) {std::cerr << "Exception caught in main: " << e.what() << std::endl;}return 0;
}

5. 日志记录

在多线程程序中,记录详细的日志是诊断问题的重要手段。可以使用日志库(如 spdlog)来记录日志信息。

示例代码:
#include <iostream>
#include <thread>
#include <spdlog/spdlog.h>void threadFunction() {try {// 模拟可能抛出异常的代码throw std::runtime_error("An error occurred in the thread");} catch (const std::exception& e) {spdlog::error("Exception caught in thread: {}", e.what());// 进行其他必要的处理}
}int main() {auto logger = spdlog::stdout_color_mt("console");std::thread t(threadFunction);t.join();return 0;
}

6. 使用线程池

线程池可以更好地管理和复用线程,减少线程创建和销毁的开销。线程池通常会处理线程中的异常,并确保线程池的正常运行。

示例代码:
#include <iostream>
#include <thread>
#include <vector>
#include <queue>
#include <functional>
#include <mutex>
#include <condition_variable>class ThreadPool {
public:ThreadPool(size_t numThreads) : stop(false) {for (size_t i = 0; i < numThreads; ++i) {threads.emplace_back([this] {while (true) {std::function<void()> task;{std::unique_lock<std::mutex> lock(queueMutex);condition.wait(lock, [this] { return stop || !tasks.empty(); });if (stop && tasks.empty()) {return;}task = std::move(tasks.front());tasks.pop();}try {task();} catch (const std::exception& e) {std::cerr << "Exception caught in thread pool: " << e.what() << std::endl;}}});}}~ThreadPool() {{std::unique_lock<std::mutex> lock(queueMutex);stop = true;}condition.notify_all();for (std::thread& t : threads) {t.join();}}template <typename Func, typename... Args>auto enqueue(Func&& func, Args&&... args) -> std::future<decltype(func(args...))> {using return_type = decltype(func(args...));auto task = std::make_shared<std::packaged_task<return_type()>>(std::bind(std::forward<Func>(func), std::forward<Args>(args)...));std::future<return_type> res = task->get_future();{std::unique_lock<std::mutex> lock(queueMutex);if (stop) {throw std::runtime_error("Enqueue on stopped ThreadPool");}tasks.emplace([task]() { (*task)(); });}condition.notify_one();return res;}private:std::vector<std::thread> threads;std::queue<std::function<void()>> tasks;std::mutex queueMutex;std::condition_variable condition;bool stop;
};void simulateWork() {throw std::runtime_error("An error occurred in the task");
}int main() {ThreadPool pool(4);std::future<void> future = pool.enqueue(simulateWork);try {future.get();} catch (const std::exception& e) {std::cerr << "Exception caught in main: " << e.what() << std::endl;}return 0;
}

总结

在并发编程中,确保异常安全需要从多个方面着手,包括异常捕获和处理、资源管理、线程同步、异常传播、日志记录和使用线程池等。通过这些方法,可以有效地处理并发环境中的异常,提高程序的稳定性和可靠性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/66482.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Navicat Premium 数据可视化

工作区&#xff0c;数据源以及图表 数据可视化是使用可视化组件&#xff08;例如图表&#xff0c;图形和地图&#xff09;的信息和数据的图形表示。 数据可视化工具提供了一种可访问的方式&#xff0c;用于查看和理解数据中的趋势&#xff0c;异常值和其他模式。 在Navicat中&…

【系统分享01】Python+Vue电影推荐系统

大家好&#xff0c;作为一名老程序员&#xff0c;今天我将带你一起走进电影推荐系统的世界&#xff0c;分享如何利用 Django REST Framework 和 Vue 搭建一套完整的电影推荐系统&#xff0c;结合 协同过滤算法&#xff0c;根据用户评分与影片喜好&#xff0c;精准推送用户可能喜…

【大数据2025】MapReduce

MapReduce 基础介绍 起源与发展&#xff1a;是 2004 年 10 月谷歌发表的 MAPREDUCE 论文的开源实现&#xff0c;最初用于大规模网页数据并行处理&#xff0c;现成为 Hadoop 核心子项目之一&#xff0c;是面向批处理的分布式计算框架。基本原理&#xff1a;分为 map 和 reduce …

主从复制

简述mysql 主从复制原理及其工作过程&#xff0c;配置一主两从并验证。 主从原理&#xff1a;MySQL 主从同步是一种数据库复制技术&#xff0c;它通过将主服务器上的数据更改复制到一个或多个从服务器&#xff0c;实现数据的自动同步。 主从同步的核心原理是将主服务器上的二…

【博客之星评选】2024年度前端学习总结

故事的开端...始于2024年第一篇前端技术博客 那故事的终末...也该结束于陪伴了我一整年的前端知识了 踏入 2025 年&#xff0c;满心激动与自豪&#xff0c;我成功闯进了《2024 年度 CSDN 博客之星总评选》的 TOP300。作为一名刚接触技术写作不久的萌新&#xff0c;这次能走到这…

《TikTok停服:信息安全警钟长鸣》

一、TikTok 停服事件回顾 2025 年 1 月 18 日晚&#xff0c;TikTok 通知美国用户&#xff0c;由于美官方禁令于 19 日起生效&#xff0c;TikTok 软件将暂时对用户停止服务。这一消息犹如一颗重磅炸弹&#xff0c;瞬间在全球范围内掀起轩然大波。美国用户对此猝不及防&#xff0…

图论DFS:黑红树

我的个人主页 {\large \mathsf{{\color{Red} 我的个人主页} } } 我的个人主页 往 {\color{Red} {\Huge 往} } 往 期 {\color{Green} {\Huge 期} } 期 文 {\color{Blue} {\Huge 文} } 文 章 {\color{Orange} {\Huge 章}} 章 DFS 算法&#xff1a;记忆化搜索DFS 算法&#xf…

C++,设计模式,【目录篇】

文章目录 1. 简介2. 设计模式的分类2.1 创建型模式&#xff08;Creational Patterns&#xff09;&#xff1a;2.2 结构型模式&#xff08;Structural Patterns&#xff09;&#xff1a;2.3 行为型模式&#xff08;Behavioral Patterns&#xff09;&#xff1a; 3. 使用设计模式…

项目实战--网页五子棋(游戏大厅)(3)

我们的游戏大厅界面主要需要包含两个功能&#xff0c;一是显示用户信息&#xff0c;二是匹配游戏按钮 1. 页面实现 hall.html <!DOCTYPE html> <html lang"ch"> <head><meta charset"UTF-8"><meta name"viewport"…

大模型UI:Gradio全解11——Chatbot:融合大模型的聊天机器人(4)

大模型UI&#xff1a;Gradio全解11——Chatbot&#xff1a;融合大模型的聊天机器人&#xff08;4&#xff09; 前言本篇摘要11. Chatbot&#xff1a;融合大模型的多模态聊天机器人11.4 使用Blocks创建自定义聊天机器人11.4.1 简单聊天机器人演示11.4.2 立即响应和流式传输11.4.…

STM32 FreeRTOS内存管理简介

在使用 FreeRTOS 创建任务、队列、信号量等对象时&#xff0c;通常都有动态创建和静态创建的方式。动态方式提供了更灵活的内存管理&#xff0c;而静态方式则更注重内存的静态分配和控制。 如果是1的&#xff0c;那么标准 C 库 malloc() 和 free() 函数有时可用于此目的&#…

【Linux系统编程】—— 深度解析进程等待与终止:系统高效运行的关键

文章目录 进程创建再次认识fork()函数fork()函数返回值 写时拷贝fork常规⽤法以及调用失败的原因 进程终⽌进程终止对应的三种情况进程常⻅退出⽅法_exit函数exit函数return退出 进程等待进程等待的必要性进程等待的⽅法 进程创建 再次认识fork()函数 fork函数初识&#xff1…

国产编辑器EverEdit -重复行

1 重复行 1.1 应用场景 在代码或文本编辑过程中&#xff0c; 经常需要快速复制当前行&#xff0c;比如&#xff0c;给对象的多个属性进行赋值。传统的做法是&#xff1a;选中行-> 复制-> 插入新行-> 粘贴&#xff0c;该操作有4个步骤&#xff0c;非常繁琐。 那有没…

NiceFish(美人鱼)

前端有 3 个版本&#xff1a; 浏览器环境移动端环境Electron 环境 服务端有 2 个版本&#xff1a; SpringBoot 版本&#xff08;已实现基于 Apache Shiro 的 RBAC 权限控制&#xff09;SpringCloud 版本 1.主要依赖 名称版本描述Angular16.2.0Angular 核心库。PrimeNG16.2…

华为ENSP:STP和链路聚合的管理与配置

这里将不再过度阐述STP和链路聚合的理论知识&#xff0c;不清楚的同学可以去观看Cisco文章中的理论知识 理论知识https://blog.csdn.net/2301_76341691/article/details/145166547?fromshareblogdetail&sharetypeblogdetail&sharerId145166547&sharereferPC&…

dl学习笔记:(4)简单神经网络

&#xff08;1&#xff09;单层正向回归网络 bx1x2z100-0.2110-0.05101-0.051110.1 接下来我们用代码实现这组线性回归数据 import torch x torch.tensor([[1,0,0],[1,1,0],[1,0,1],[1,1,1]], dtype torch.float32) z torch.tensor([-0.2, -0.05, -0.05, 0.1]) w torch.…

三、华为交换机 Hybrid

一、Hybrid功能 Hybrid口既可以连接普通终端的接入链路&#xff08;类似于Access接口&#xff09;&#xff0c;又可以连接交换机间的干道链路&#xff08;类似于Trunk接口&#xff09;。它允许多个VLAN的帧通过&#xff0c;并可以在出接口方向将某些VLAN帧的标签剥掉&#xff0…

Tensor 基本操作1 | PyTorch 深度学习实战

目录 创建 Tensor常用操作unsqueezesqueezeSoftmax代码1代码2代码3 argmaxitem 创建 Tensor 使用 Torch 接口创建 Tensor import torch参考&#xff1a;https://pytorch.org/tutorials/beginner/basics/tensorqs_tutorial.html 常用操作 unsqueeze 将多维数组解套&#xf…

Grafana系列之面板接入Prometheus Alertmanager

关于Grafana的仪表板Dashboard&#xff0c;以及面板Panel&#xff0c;参考Grafana系列之Dashboard。可以直接在面板上创建Alert&#xff0c;即所谓的Grafana Alert&#xff0c;参考Grafana系列之Grafana Alert。除了Grafana Alert外&#xff0c;面板也可接入Prometheus Alertma…

Windows 上安装 MongoDB 的 zip 包

博主介绍&#xff1a; 大家好&#xff0c;我是想成为Super的Yuperman&#xff0c;互联网宇宙厂经验&#xff0c;17年医疗健康行业的码拉松奔跑者&#xff0c;曾担任技术专家、架构师、研发总监负责和主导多个应用架构。 近期专注&#xff1a; RPA应用研究&#xff0c;主流厂商产…