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;
}

总结

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何选择Ubuntu版本

一、为什么要选择Ubuntu系统&#xff1f; CentOS官方已全面停止维护CentOS Linux项目 。具体来说&#xff0c;CentOS 8已于2021年12月31日停止维护&#xff0c;而CentOS 7则在2024年6月30日结束了生命周期 。这意味着这些版本不再接收官方的安全更新、bug修复或技术支持 二、…

计算机视觉算法实战——视频分析(Video Analysis)

✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连✨ ​​​​​​ ​​​​​​​​​​​​ ​​​​​ 视频分析是计算机视觉中的一个重要领域&#xff0c;旨在从视频数据中提取有用的信息&…

O2O同城系统架构与功能分析

2015工作至今&#xff0c;10年资深全栈工程师&#xff0c;CTO&#xff0c;擅长带团队、攻克各种技术难题、研发各类软件产品&#xff0c;我的代码态度&#xff1a;代码虐我千百遍&#xff0c;我待代码如初恋&#xff0c;我的工作态度&#xff1a;极致&#xff0c;责任&#xff…

讲一下ZooKeeper的持久化机制?

大家好&#xff0c;我是锋哥。今天分享关于【讲一下ZooKeeper的持久化机制&#xff1f;】面试题。希望对大家有帮助&#xff1b; 讲一下ZooKeeper的持久化机制&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 ZooKeeper 是一个开源的分布式协调服务&…

C++ 文字识别OCR

一.引言 文字识别&#xff0c;也称为光学字符识别&#xff08;Optical Character Recognition, OCR&#xff09;&#xff0c;是一种将不同形式的文档&#xff08;如扫描的纸质文档、PDF文件或数字相机拍摄的图片&#xff09;中的文字转换成可编辑和可搜索的数据的技术。随着技…

数据库(MySQL)练习

数据库&#xff08;MySQL&#xff09;练习 一、练习1.15练习1.16练习 二、注意事项2.1 第四天 一、练习 1.15练习 win11安装配置MySQL超详细教程: https://baijiahao.baidu.com/s?id1786910666566008458&wfrspider&forpc 准备工作&#xff1a; mysql -uroot -p #以…

【HTML+CSS+JS+VUE】web前端教程-35-字体图标

优点: 轻量性:加载速度快,减少http请求 灵活性:可以利用CSS设置大小颜色等 兼容性:网页字体支持所有现代浏览器,包括IE低版本 使用字体图标: 1、注册账户并登录 2、选取图标或搜索图标 3、添加购物车 4、下载代码 5、选择font-class引用 iconfont Logo:https://www.ic…

YOLOv8模型改进 第二十九讲 添加可学习小波变换节点 Learnable Wavelet Transform Node 提高小目标检测能力,增强细节特征

在图像去模糊领域&#xff0c;多尺度架构虽被广泛应用&#xff0c;但存在固有缺陷。在渐进恢复过程中&#xff0c;由于底层空间分辨率小&#xff0c;向上传递的特征语义精确但空间模糊&#xff0c;导致多尺度网络在空间细节恢复能力上受限。为提升高频细节部分的恢复质量&#…

数据库基础实验1(创建表,设置外键,检查,不为空,主键等约束)安装mysql详细步骤

安装MySQL详细步骤 1. 下载 MySQL 安装程序 访问 MySQL 官方网站&#xff1a;MySQL Downloads。在下载页面&#xff0c;选择 "MySQL Community (GPL) Downloads"。在 "MySQL Community Server" 部分&#xff0c;根据你的操作系统&#xff08;Windows&…

CSRF(跨站请求伪造)深度解析

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

详解如何自定义 Android Dex VMP 保护壳

版权归作者所有&#xff0c;如有转发&#xff0c;请注明文章出处&#xff1a;https://cyrus-studio.github.io/blog/ 前言 Android Dex VMP&#xff08;Virtual Machine Protection&#xff0c;虚拟机保护&#xff09;壳是一种常见的应用保护技术&#xff0c;主要用于保护 And…

rabbitmqp安装延迟队列

在RabbitMQ中&#xff0c;延迟队列是一种特殊的队列类型。当消息被发送到此类队列后&#xff0c;不会立即投递给消费者&#xff0c;而是会等待预设的一段时间&#xff0c;待延迟期满后才进行投递。这种队列在多种场景下都极具价值&#xff0c;比如可用于处理需要在特定时间触发…

向量数据库如何助力Text2SQL处理高基数类别数据

01. 导语 Agent工作流和 LLMs &#xff08;大语言模型&#xff09;的出现&#xff0c;让我们能够以自然语言交互的模式执行复杂的SQL查询&#xff0c;并彻底改变Text2SQL系统的运行方式。其典型代表是如何处理High-Cardinality Categorical Data &#xff08;高基数类别数据&am…

Docker实践:部署Docker管理工具DockerUI

Docker实践&#xff1a;部署Docker管理工具DockerUI 前言一、DockerUI介绍1.1 DockerUI概述1.2 镜像说明 二、检查本地Docker环境三、拉取DockerUI镜像四、创建DockerUI容器五、访问DockerUI六、DockerUI的基本使用6.1 查询宿主机容器情况6.2 查询Docker镜像列表6.3 查看容器配…

【excel】VBA股票数据获取(搜狐股票)

文章目录 一、序二、excel 自动刷新股票数据三、付费获取 一、序 我其实不会 excel 的函数和 visual basic。因为都可以用matlab和python完成。 今天用了下VBA&#xff0c;还挺不错的。分享下。 上传写了个matlab获取股票数据的&#xff0c;是雅虎财经的。这次是搜狐股票的数…

解锁企业数据管理统一身份认证难题,EasyMR助力企业敏捷提效

在数字经济迅猛发展的当下&#xff0c;企业数据量正以令人惊叹的速度持续增长。据IDC研究显示&#xff0c;至2025年&#xff0c;全球数据总量预计将超175 ZB。数据的爆发式增长对企业而言&#xff0c;既是机遇&#xff0c;更是巨大挑战。 如今&#xff0c;大数据已然成为企业决…

IntelliJ IDEA Type Hierarchy Scope Pattern 学习指南

IntelliJ IDEA Type Hierarchy Scope Pattern 学习指南 什么是 Type Hierarchy&#xff1f; Type Hierarchy 是 IntelliJ IDEA 提供的一个工具&#xff0c;允许开发者查看某个类的继承关系及其实现的接口结构。它是理解类关系的重要工具&#xff0c;尤其在处理复杂的继承体系…

ukui-quick 计数器

作品简介 使用ukui-quick框架进行开发&#xff0c;实现了在任务栏中计数器的插件&#xff0c;方便用户的日常使用。 技术架构 用于实现一个具有点击计数功能的QML应用程序。这个架构将包括C后端和QML前端&#xff0c;通过Qt的信号和属性绑定机制进行交互。 实现过程 开发环…

Flutter:封装ActionSheet 操作菜单

演示效果图 action_sheet_util.dart import package:ducafe_ui_core/ducafe_ui_core.dart; import package:flutter/material.dart; import package:demo/common/index.dart;class ActionSheetUtil {/// 底部操作表/// [context] 上下文/// [title] 标题/// [items] 选项列表 …

【混合开发】CefSharp+Vue 解决Cookie问题

问题表现 使用Element-admin架构搭建Vue前端项目&#xff0c;在与CefSharp搭配时&#xff0c;出现无法使用cookie的问题。 无法将token存入cookiecookie无法被读取 如下图&#xff0c;Cookies下显示file://。 正常的Cookies显示&#xff0c;Cookies显示为http://域名&#x…