C++多线程相关应用

简介: C++多线程相关应用

C++多线程相关应用


一、多线程基础

1. 线程创建与管理

#include <thread>
#include <iostream>

void task(int id) {
   
    std::cout << "Thread " << id << " executing\n";
}

int main() {
   
    std::thread t1(task, 1);  // 创建线程
    std::thread t2([](){
          // Lambda表达式创建线程
        std::cout << "Lambda thread\n";
    });

    t1.join();  // 等待线程结束
    t2.join();

    // detach示例(谨慎使用)
    std::thread t3([]{
    /* 后台任务 */ });
    t3.detach();
}

2. 线程生命周期管理

  • join():阻塞等待线程结束
  • detach():分离线程(失去控制权)
  • RAII包装器:
    class ThreadGuard {
         
      std::thread& t;
    public:
      explicit ThreadGuard(std::thread& t_) : t(t_) {
         }
      ~ThreadGuard() {
         
          if(t.joinable()) {
         
              t.join();  // 或根据需求选择detach
          }
      }
    };
    

二、互斥量(Mutex)应用

1. 基础锁机制

#include <mutex>

std::mutex mtx;
int shared_data = 0;

void safe_increment() {
   
    std::lock_guard<std::mutex> lock(mtx);  // RAII自动解锁
    ++shared_data;
}

// 递归锁示例
std::recursive_mutex rec_mtx;
void recursive_func(int n) {
   
    std::lock_guard<std::recursive_mutex> lock(rec_mtx);
    if(n > 0) recursive_func(n-1);
}

2. 死锁预防

// 使用std::lock同时锁定多个互斥量
std::mutex mtx1, mtx2;

void safe_process() {
   
    std::unique_lock<std::mutex> lock1(mtx1, std::defer_lock);
    std::unique_lock<std::mutex> lock2(mtx2, std::defer_lock);
    std::lock(lock1, lock2);  // 原子化锁定

    // 临界区操作
}

三、条件变量(Condition Variable)

1. 生产者-消费者模型

#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();  // 通知消费者
    }
}

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 << std::endl;
        if(data == 4) break;
    }
}

2. 条件变量使用要点

  • 始终在循环中检查条件
  • 使用notify_all()广播通知多个等待线程
  • 注意通知时机,避免丢失信号

四、原子变量(Atomic)

1. 基础使用

#include <atomic>

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

void atomic_increment() {
   
    for(int i=0; i<1000; ++i) {
   
        counter.fetch_add(1, std::memory_order_relaxed);
    }
}

// 测试代码
std::thread t1(atomic_increment);
std::thread t2(atomic_increment);
t1.join(); t2.join();
std::cout << "Final counter: " << counter << std::endl;  // 正确输出2000

2. 内存序选择

内存序 特性 使用场景
memory_order_relaxed 无顺序保证 计数器等简单操作
memory_order_consume 数据依赖排序 很少使用
memory_order_acquire 加载操作前的访问可见 锁获取
memory_order_release 存储操作后的修改可见 锁释放
memory_order_seq_cst 全局顺序一致(默认) 需要严格顺序的场景

五、综合应用案例

1. 线程池实现

#include <vector>
#include <future>

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, class... Args>
    auto enqueue(F&& f, Args&&... args) -> std::future<decltype(f(args...))> {
   
        using return_type = decltype(f(args...));

        auto task = std::make_shared<std::packaged_task<return_type()>>(
            std::bind(std::forward<F>(f), std::forward<Args>(args)...)
        );

        std::future<return_type> res = task->get_future();
        {
   
            std::lock_guard<std::mutex> lock(queue_mutex);
            if(stop) throw std::runtime_error("enqueue on stopped ThreadPool");

            tasks.emplace([task](){
    (*task)(); });
        }
        condition.notify_one();
        return res;
    }

    ~ThreadPool() {
   
        {
   
            std::lock_guard<std::mutex> lock(queue_mutex);
            stop = true;
        }
        condition.notify_all();
        for(std::thread &worker : workers)
            worker.join();
    }
};

六、性能优化与陷阱

1. 锁粒度控制

// 错误示例:大粒度锁
std::mutex big_lock;
void process_data() {
   
    std::lock_guard<std::mutex> lock(big_lock);  // 锁住整个函数
    // 长时间操作...
}

// 优化:细粒度锁
struct DataPart {
   
    std::mutex mtx;
    int value;
};
DataPart part1, part2;

void process_part(DataPart& part) {
   
    std::lock_guard<std::mutex> lock(part.mtx);
    // 操作单个数据部分
}

2. 虚假唤醒防护

std::condition_variable cv;
bool ready = false;  // 必须的条件判断变量

// 正确写法
cv.wait(lock, []{
    return ready; }); 

// 错误写法(可能虚假唤醒)
while(!ready) cv.wait(lock);

3. 原子操作陷阱

std::atomic<bool> flag(false);
int non_atomic_data = 0;

void thread1() {
   
    non_atomic_data = 42;          // ①
    flag.store(true);              // ②
}

void thread2() {
   
    if(flag.load()) {
                 // ③
        std::cout << non_atomic_data;  // ④ 可能看到0或42
    }
}
// 需要memory_order_release/acquire保证可见性

七、现代C++新特性

1. std::async异步操作

#include <future>

auto future = std::async(std::launch::async, []{
   
    std::this_thread::sleep_for(1s);
    return 42;
});

// 等待结果
std::cout << future.get() << std::endl;

2. 读写锁(C++17)

#include <shared_mutex>

std::shared_mutex rw_mutex;
void reader() {
   
    std::shared_lock lock(rw_mutex);  // 共享锁
    // 读操作...
}

void writer() {
   
    std::unique_lock lock(rw_mutex);  // 独占锁
    // 写操作...
}

八、调试与检测工具

  1. Thread Sanitizer(TSan)

    clang++ -fsanitize=thread -g program.cpp
    
  2. Mutex死锁检测

    // 使用std::scoped_lock(C++17)
    std::mutex mtx1, mtx2;
    std::scoped_lock lock(mtx1, mtx2);  // 自动死锁避免
    
  3. 性能分析工具

  • Perf
  • Intel VTune
  • Valgrind的DRD工具
目录
相关文章
|
存储 负载均衡 算法
基于 C++ 语言的迪杰斯特拉算法在局域网计算机管理中的应用剖析
在局域网计算机管理中,迪杰斯特拉算法用于优化网络路径、分配资源和定位故障节点,确保高效稳定的网络环境。该算法通过计算最短路径,提升数据传输速率与稳定性,实现负载均衡并快速排除故障。C++代码示例展示了其在网络模拟中的应用,为企业信息化建设提供有力支持。
409 15
|
9月前
|
Ubuntu API C++
C++标准库、Windows API及Ubuntu API的综合应用
总之,C++标准库、Windows API和Ubuntu API的综合应用是一项挑战性较大的任务,需要开发者具备跨平台编程的深入知识和丰富经验。通过合理的架构设计和有效的工具选择,可以在不同的操作系统平台上高效地开发和部署应用程序。
325 11
|
Java
线程池是什么?线程池在实际工作中的应用
总的来说,线程池是一种有效的多线程处理方式,它可以提高系统的性能和稳定性。在实际工作中,我们需要根据任务的特性和系统的硬件能力来合理设置线程池的大小,以达到最佳的效果。
358 18
|
算法 Serverless 数据处理
从集思录可转债数据探秘:Python与C++实现的移动平均算法应用
本文探讨了如何利用移动平均算法分析集思录提供的可转债数据,帮助投资者把握价格趋势。通过Python和C++两种编程语言实现简单移动平均(SMA),展示了数据处理的具体方法。Python代码借助`pandas`库轻松计算5日SMA,而C++代码则通过高效的数据处理展示了SMA的计算过程。集思录平台提供了详尽且及时的可转债数据,助力投资者结合算法与社区讨论,做出更明智的投资决策。掌握这些工具和技术,有助于在复杂多变的金融市场中挖掘更多价值。
636 12
|
编译器 数据安全/隐私保护 C++
【C++面向对象——继承与派生】派生类的应用(头歌实践教学平台习题)【合集】
本实验旨在学习类的继承关系、不同继承方式下的访问控制及利用虚基类解决二义性问题。主要内容包括: 1. **类的继承关系基础概念**:介绍继承的定义及声明派生类的语法。 2. **不同继承方式下对基类成员的访问控制**:详细说明`public`、`private`和`protected`继承方式对基类成员的访问权限影响。 3. **利用虚基类解决二义性问题**:解释多继承中可能出现的二义性及其解决方案——虚基类。 实验任务要求从`people`类派生出`student`、`teacher`、`graduate`和`TA`类,添加特定属性并测试这些类的功能。最终通过创建教师和助教实例,验证代码
525 5
|
缓存 Java 开发者
Java多线程并发编程:同步机制与实践应用
本文深入探讨Java多线程中的同步机制,分析了多线程并发带来的数据不一致等问题,详细介绍了`synchronized`关键字、`ReentrantLock`显式锁及`ReentrantReadWriteLock`读写锁的应用,结合代码示例展示了如何有效解决竞态条件,提升程序性能与稳定性。
983 6
|
安全 Java 开发者
Java 多线程并发控制:深入理解与实战应用
《Java多线程并发控制:深入理解与实战应用》一书详细解析了Java多线程编程的核心概念、并发控制技术及其实战技巧,适合Java开发者深入学习和实践参考。
396 8
|
数据采集 存储 数据处理
Python中的多线程编程及其在数据处理中的应用
本文深入探讨了Python中多线程编程的概念、原理和实现方法,并详细介绍了其在数据处理领域的应用。通过对比单线程与多线程的性能差异,展示了多线程编程在提升程序运行效率方面的显著优势。文章还提供了实际案例,帮助读者更好地理解和掌握多线程编程技术。
|
监控 Java 数据库连接
Java线程管理:守护线程与用户线程的区分与应用
在Java多线程编程中,线程可以分为守护线程(Daemon Thread)和用户线程(User Thread)。这两种线程在行为和用途上有着明显的区别,了解它们的差异对于编写高效、稳定的并发程序至关重要。
486 2