第16天:C++多线程完全指南 - 从基础到现代并发编程

第16天:C++多线程完全指南 - 从基础到现代并发编程

一、多线程基础概念

1. 线程创建与管理(C++11)

#include <iostream>
#include <thread>

void hello() {
    std::cout << "Hello from thread " 
              << std::this_thread::get_id() << "\n";
}

int main() {
    std::thread t1(hello);
    std::thread t2([](){
        std::cout << "Lambda thread running\n";
    });
    
    t1.join();  // 等待线程完成
    t2.join();
    
    // 输出可能交错:
    // Hello from thread 140245230233344
    // Lambda thread running
}

2. 并发与并行区别

  • 并发:交替处理多个任务(单核)
  • 并行:同时处理多个任务(多核)
// 查看硬件支持线程数
unsigned int n = std::thread::hardware_concurrency();
std::cout << n << " concurrent threads supported\n";

二、线程同步核心机制

1. 互斥锁(mutex)与RAII

#include <mutex>

std::mutex mtx;
int shared_data = 0;

void safe_increment() {
    std::lock_guard<std::mutex> lock(mtx); // 自动释放锁
    ++shared_data;  // 临界区操作
}

int main() {
    std::thread threads[10];
    for (auto& t : threads) {
        t = std::thread(safe_increment);
    }
    for (auto& t : threads) {
        t.join();
    }
    std::cout << "Final value: " << shared_data; // 正确输出10
}

2. 条件变量(生产者-消费者模式)

#include <queue>
#include <condition_variable>

std::mutex mtx;
std::condition_variable cv;
std::queue<int> data_queue;

void producer() {
    for (int i=0; i<5; ++i) {
        {
            std::lock_guard<std::mutex> lock(mtx);
            data_queue.push(i);
        }
        cv.notify_one();  // 通知消费者
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
}

void consumer() {
    while(true) {
        std::unique_lock<std::mutex> lock(mtx);
        cv.wait(lock, []{ return !data_queue.empty(); });
        
        int data = data_queue.front();
        data_queue.pop();
        lock.unlock();
        
        std::cout << "Consumed: " << data << "\n";
        if(data == 4) break;
    }
}

三、现代C++并发特性

1. 异步任务(std::async)

#include <future>

int compute(int x) {
    return x * x;
}

int main() {
    auto future = std::async(std::launch::async, compute, 12);
    std::cout << "Result: " << future.get();  // 输出144
}

2. 原子操作(std::atomic)

#include <atomic>

std::atomic<int> counter(0);  // 无需锁的线程安全计数器

void increment() {
    for (int i=0; i<100000; ++i) {
        ++counter;  // 原子操作
    }
}

// 测试:两个线程同时递增
// 最终结果正确为200000

四、线程安全设计模式

1. 线程局部存储(thread_local)

thread_local int tls_var = 0;  // 每个线程独立副本

void thread_func() {
    ++tls_var;
    std::cout << "Thread " << std::this_thread::get_id() 
              << ": " << tls_var << "\n";
}

// 每个线程输出自己的递增结果

2. 线程池实现(C++17)

#include <vector>
#include <functional>
#include <queue>

class ThreadPool {
    std::vector<std::thread> workers;
    std::queue<std::function<void()>> tasks;
    std::mutex queue_mutex;
    std::condition_variable condition;
    bool stop = false;
    
public:
    ThreadPool(size_t threads) {
        for(size_t i=0; i<threads; ++i) {
            workers.emplace_back([this]{
                while(true) {
                    std::function<void()> task;
                    {
                        std::unique_lock<std::mutex> lock(queue_mutex);
                        condition.wait(lock, [this]{ 
                            return stop || !tasks.empty(); 
                        });
                        if(stop && tasks.empty()) return;
                        task = std::move(tasks.front());
                        tasks.pop();
                    }
                    task();
                }
            });
        }
    }
    
    template<class F>
    void enqueue(F&& f) {
        {
            std::lock_guard<std::mutex> lock(queue_mutex);
            tasks.emplace(std::forward<F>(f));
        }
        condition.notify_one();
    }
    
    ~ThreadPool() {
        {
            std::lock_guard<std::mutex> lock(queue_mutex);
            stop = true;
        }
        condition.notify_all();
        for(auto& worker : workers)
            worker.join();
    }
};

五、并发编程陷阱与调试

1. 死锁检测示例

std::mutex m1, m2;

void thread_A() {
    std::lock_guard<std::mutex> lock1(m1);
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    std::lock_guard<std::mutex> lock2(m2); // 可能死锁点
}

void thread_B() {
    std::lock_guard<std::mutex> lock2(m2);
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    std::lock_guard<std::mutex> lock1(m1); // 可能死锁点
}

// 解决方案:使用std::lock同时锁定多个互斥量
void safe_lock() {
    std::lock(m1, m2);
    std::lock_guard<std::mutex> lock1(m1, std::adopt_lock);
    std::lock_guard<std::mutex> lock2(m2, std::adopt_lock);
}

六、现代C++并发增强

1. C++20信号量(semaphore)

#include <semaphore>

std::counting_semaphore<5> sem(3);  // 允许3个同时访问

void limited_thread() {
    sem.acquire();
    // 访问受限资源
    sem.release();
}

2. 屏障(C++20 barrier)

std::barrier sync_point(3);  // 等待3个线程到达

void worker() {
    // Phase 1
    sync_point.arrive_and_wait();
    
    // Phase 2(所有线程完成Phase1后继续)
}

七、常见问题解答

Q:如何检测数据竞争?

  • 使用ThreadSanitizer编译:
g++ -fsanitize=thread -g -O1 program.cpp
  • 示例输出:
WARNING: ThreadSanitizer: data race

Q:std::mutex和std::shared_mutex区别?

  • std::mutex:独占锁
  • std::shared_mutex:读写锁(C++17)
std::shared_mutex smtx;

// 写操作使用独占锁
{
    std::unique_lock lock(smtx);
    data = new_value;
}

// 读操作使用共享锁
{
    std::shared_lock lock(smtx);
    read_data = data;
}

八、今日总结

✅ 核心掌握:

  • 🧵 线程生命周期管理(创建、等待、分离)
  • 🔒 同步原语使用场景(mutex/atomic/condition_variable)
  • 🚧 典型并发问题检测与预防(死锁、数据竞争)

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

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

相关文章

GitCode 助力 JeeSite:开启企业级快速开发新篇章

项目仓库&#xff08;点击阅读原文链接可直达前端仓库&#xff09; https://gitcode.com/thinkgem/jeesite 企业级快速开发的得力助手&#xff1a;JeeSite 快速开发平台 JeeSite 不仅仅是一个普通的后台开发框架&#xff0c;而是一套全面的企业级快速开发解决方案。后端基于 …

EasyRTC:支持任意平台设备的嵌入式WebRTC实时音视频通信SDK解决方案

随着互联网技术的飞速发展&#xff0c;实时音视频通信已成为各行各业数字化转型的核心需求之一。无论是远程办公、在线教育、智慧医疗&#xff0c;还是智能安防、直播互动&#xff0c;用户对低延迟、高可靠、跨平台的音视频通信需求日益增长。 一、WebRTC与WebP2P&#xff1a;实…

【Qt】MVC设计模式

目录 一、搭建MVC框架 二、创建数据库连接单例类SingleDB 三、数据库业务操作类model设计 四、control层&#xff0c;关于model管理类设计 五、view层即为窗口UI类 一、搭建MVC框架 里面的bin、lib、database文件夹以及sqlite3.h与工程后缀为.pro文件的配置与上次发的文章…

使用C#控制台调用本地部署的DeepSeek

1、背景 春节期间大火的deepseek&#xff0c;在医疗圈也是火的不要不要的。北京这边的医院也都在搞“deepseek竞赛”。友谊、北医三院等都已经上了&#xff0c;真是迅速啊&#xff01; C#也是可以进行对接&#xff0c;并且非常简单。 2、具体实现 1、使用Ollama部署DeepSeek…

接口测试工具:postman详解

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 Postman 是一款功能强大的 API 开发和测试工具&#xff0c;以下是一些高级用法的详细介绍和操作步骤。 一、环境和全局变量 环境变量允许你设置特定于环境&#…

ERP系统的库存模块业务逻辑及设计

传统上通常将“库存管理”理解为对物料的进、出、存的业务管理&#xff0c;但这种理解在ERP系统中是不全面的。 APICS词汇中对库存的定义是“以支持生产、维护、操作和客户服务为目的而存储的各种物料&#xff0c;包括原材料和在制品、维修件和生产消耗、成品和备件等”​。库…

软件安全性测试类型分享,第三方软件测试机构如何进行安全性测试?

在数字化时代&#xff0c;软件的安全性至关重要&#xff0c;因此软件产品安全性测试必不可少。软件安全性测试是指针对软件系统的漏洞、弱点及其他安全隐患进行评估和检测的过程。它旨在发现潜在的安全问题&#xff0c;以保护软件和用户的利益。通过系统化的测试&#xff0c;企…

自由学习记录(40)

virtual的重写能力&#xff0c;&#xff0c;这在剥离Player方法和成员变量的时候&#xff0c;起的作用很灵活&#xff0c;敌人默认可以继承这些规则&#xff0c;但只是默认&#xff0c;自己要修改的话和原来不会产生半点联系&#xff0c;这个确实厉害 Cinemachine Virtual Came…

神经网络|(十一)|神经元和神经网络

【1】引言 前序已经了解了基本的神经元知识&#xff0c;相关文章链接为&#xff1a; 神经网络|(一)加权平均法&#xff0c;感知机和神经元-CSDN博客 神经网络|(二)sigmoid神经元函数_sigmoid函数绘制-CSDN博客 神经网络|(三)线性回归基础知识-CSDN博客 把不同的神经元通过…

【Python】基础语法三

> 作者&#xff1a;დ旧言~ > 座右铭&#xff1a;松树千年终是朽&#xff0c;槿花一日自为荣。 > 目标&#xff1a;了解Python的函数、列表和数组。 > 毒鸡汤&#xff1a;有些事情&#xff0c;总是不明白&#xff0c;所以我不会坚持。早安! > 专栏选自&#xff…

PHP使用Redis实战实录2:Redis扩展方法和PHP连接Redis的多种方案

PHP使用Redis实战实录系列 PHP使用Redis实战实录1&#xff1a;宝塔环境搭建、6379端口配置、Redis服务启动失败解决方案PHP使用Redis实战实录2&#xff1a;Redis扩展方法和PHP连接Redis的多种方案 Redis扩展方法和PHP连接Redis的多种方案 一、Redis扩展方法二、php操作Redis…

kubernetes 初学命令

基础命令 kubectl 运维命令常用&#xff1a; #查看pod创建过程以及相关日志 kubectl describe pod pod-command -n dev #查看某个pod&#xff0c;以yaml格式展示结果 kubectl get pod nginx -o yaml #查看pod 详情 以及对应的集群IP地址 kubectl get pods -o wide 1. kubetc…

[C++_] set | map | unordered_map

前文回顾&#xff1a; 【C】详解 set | multiset 【C】关联容器探秘&#xff1a;Map与Multimap详解 在 C 中&#xff0c;map 和 unordered_map 都是存储键值对的关联容器&#xff0c;但它们的实现和特性有显著区别。如下&#xff1a; 1. 底层实现与有序性 map 基于红黑树&a…

【计算机网络】TCP三次握手,四次挥手以及SYN,ACK,seq,以及握手次数理解

TCP三次握手图解 描述 第一次握手&#xff1a;客户端请求建立连接&#xff0c;发送同步报文(SYN1)&#xff0c;同时随机一个seqx作为初始序列号&#xff0c;进入SYN_SENT状态&#xff0c;等待服务器确认 第二次握手&#xff1a;服务端收到请求报文&#xff0c;如果同意建立连接…

DVWA -第二关-命令执行

这里是个ping命令的提交框 我们在输入ping命令的时候&#xff0c;同时执行其他命令操作 low 输入127.0.0.||ipconfig 消除乱码的方法&#xff1a;修改dvwaPage.inc.php文件中的”charsetutf-8”&#xff0c;修改”charsetGB2312” 可以显示出来&#xff0c;初级没有过滤 m…

Kibana:Spotify Wrapped 第二部分:深入挖掘数据

作者&#xff1a;来自 Elastic Philipp Kahr 我们将比以往更深入地探究你的 Spotify 数据并探索你甚至不知道存在的联系。 在由 Iulia Feroli 撰写的本系列的第一部分中&#xff0c;我们讨论了如何获取 Spotify Wrapped 数据并在 Kibana 中对其进行可视化。在第 2 部分中&#…

Week2 Using the Java Collection Libraries Lecture 2

1. Java为数据结构编程提供了哪些支持&#xff1f; &#xff08;1&#xff09;Java 提供了丰富的数据结构类&#xff0c;通过 Java 集合框架&#xff08;Java Collections Framework&#xff09; 来实现&#xff0c;常见的包括&#xff1a; Java 集合框架&#xff08;Java Col…

武汉大学生命科学学院与谱度众合(武汉)生命科技有限公司举行校企联培座谈会

2025年2月21日下午&#xff0c;武汉大学生命科学学院与谱度众合&#xff08;武汉&#xff09;生命科技有限公司&#xff08;以下简称“谱度众合”&#xff09;在学院学术厅举行校企联培专业学位研究生合作交流会。武汉大学生命科学学院副院长刘星教授、生命科学学院周宇教授、产…

【随时随地学算法】本地部署hello-algo结合内网穿透远程学习新体验

文章目录 前言1.关于hello-algo2.安装Docker和Docker compose3.本地部署hello-algo4. hello-algo本地访问5.cpolar内网穿透工具安装6.创建远程连接公网地址7.固定Uptime Kuma公网地址 前言 本篇文章主要介绍如何在本地部署hello-algo算法学习必备项目&#xff0c;并结合cpol…

加油站小程序实战教程03站点管理

目录 1 创建数据源2 搭建后台功能2.1 搭建类目配置功能2.2 配置系统信息2.3 配置站点功能2.4 配置油号功能2.5 配置油枪功能2.6 配置站点菜单2.7 设置站点的操作列 总结 在开发小程序的时候&#xff0c;通常需要先拆解业务对应我们的需求分析&#xff0c;根据需求来推导数据结构…