C++线程一次创建 多次使用 避开循环场景中 线程多次创建销毁的开销

Posted Zetaa

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++线程一次创建 多次使用 避开循环场景中 线程多次创建销毁的开销相关的知识,希望对你有一定的参考价值。

使用场景举例:一百万次循环,每次循环中需要对两个一千万维度的向量进行内积运算。注意,可能是由于某种原因(比如是迭代算法),该场景必须顺序执行一百万次循环。在这种场景下,希望使用多线程进行计算加速,具体就是对每次一循环中的计算进行多线程计算。具体地,主线程将每一次循环中的两个一千万维度向量的内积运算切割为5个二百万维度的子向量分别交由5个子线程进行内积运算,得到五个子向量内积。然后主线程拿到5个子向量内积,对这5个值进行求和,结果即为原始的两个一千万维度向量的内积结果。然后进行下一轮循环…。

下面的代码中有三个填空部分,分别是:1)主线程在唤醒子线程之前的准备工作的代码,2)子线程干活具体内容的代码,3)主线程在一轮循环中子线程全部结束后(只是一轮)后的处理工作的代码。

// 线程一次创建,多次使用
#include <iostream>           // std::cout
#include <thread>             // std::thread
#include <mutex>              // std::mutex, std::unique_lock
#include <condition_variable> // std::condition_variable
#include <chrono>
#include <vector>
using namespace std;

const int numOfThreads = 4; // 子线程总数量
std::mutex mtx[numOfThreads]; // 主线程唤醒子线程的锁
std::mutex mtx_main[numOfThreads]; // 子线程唤醒主线程的锁
std::condition_variable cv_main[numOfThreads];//子线程唤醒主线程的条件变量 
std::condition_variable cv[numOfThreads];//主线程唤醒子线程的条件变量 
bool ready[numOfThreads] =  false ;// 主线程设置,子线程查看的标记
bool ready_main[numOfThreads] =  false ;// 子线程设置,主线程查看的标记
volatile bool done = false;// 主线程设置,子线程查看的标记。具体用于表示主线程总体任务是否结束

void print_id(int id) 
    while (1) 
        
        std::unique_lock<std::mutex> lck(mtx[id]);// 用一个mutex锁创建一个 unique_lock
        if (done) break; // done的值由主线程设置,done=true 则结束子线程
        while (!ready[id]) cv[id].wait(lck);// 等待唤醒
        if (done) break; // 双重保险,否则可能发生死锁,暂不明原因。 done的值由主线程设置,done=true 则结束子线程    
        /*
        ... 这里写线程干活的代码
        */
        //std::this_thread::sleep_for(std::chrono::milliseconds(1));// 当前线程睡眠
        ready[id] = false;
        ready_main[id] = true;
        cv_main[id].notify_one();
    



int main()

    vector<thread> threads;
    for (int i = 0; i < numOfThreads; ++i)// 创建线程
        threads.push_back(thread(print_id, i));
    int n = 400; // 线程1次创建,重复使用 n 次
    int cnt = 0; // 计数器
    while (cnt < n) 
        /*
        ... 这里写唤醒子线程的准备工作的代码
        */
        for (int i = 0; i < numOfThreads; i++) // 唤醒子线程
            ready[i] = true;
            cv[i].notify_one();
        
        for (int i = 0; i < numOfThreads; i++)  //主线程通过阻塞等待本轮所有线程执行完毕
            std::unique_lock<std::mutex> lck(mtx_main[i]);
            while (!ready_main[i]) cv_main[i].wait(lck);// 等待 第 i 个线程唤醒
        
        /*
        ... 这里写一轮子线程全部执行完成后的处理工作
        */
        
        cnt++;
    
    done = true;// 主线程任务完成
    for (int i = 0; i < numOfThreads; i++) //双重保险,否则可能发生死锁,暂不明原因。 唤醒子线程
        ready[i] = true;
        cv[i].notify_one();
    

    for (auto& th : threads) th.join(); // 等待所有线程结束

    cout << "everything done" << endl;

    return 0;

以上是关于C++线程一次创建 多次使用 避开循环场景中 线程多次创建销毁的开销的主要内容,如果未能解决你的问题,请参考以下文章

怎么让当前线程等待另一个线程完成之后再去执行

jmeter逻辑控制器-仅一次控制器交替控制器

在 C++ 中的线程内启动和停止循环

Android HandlerThread 源代码分析

C++ - 如何找出当前线程的创建位置?

C++每日一练3.创建一个线程