c++ 线程池

当涉及到多线程编程时,代码的正确性和可靠性至关重要。下面是对代码的详细解释:

  1. ThreadPool 类的构造函数:

    • ThreadPool(size_t numThreads) 构造函数接受一个整数参数 numThreads,表示线程池应该包含的工作线程数量。
    • 使用一个循环来创建指定数量的工作线程。每个工作线程都是一个 lambda 函数,它会循环地从任务队列中获取任务并执行。
    • 在 lambda 函数中,首先会等待任务队列非空或者收到停止信号的条件变量通知。这里使用 condition.wait(lock, [this] { return stop || !tasks.empty(); }) 来等待条件满足。lock 是一个 std::unique_lock 对象,它在等待期间自动释放互斥锁,以便其他线程可以访问任务队列。
    • 如果收到停止信号并且任务队列为空,则工作线程退出循环,线程函数结束。
    • 否则,从任务队列中获取一个任务,并执行该任务。
  2. ThreadPool 类的析构函数:

    • 析构函数首先设置停止信号 stop 为 true,以通知所有工作线程停止执行任务。
    • 然后,通过调用 condition.notify_all() 来唤醒所有等待条件变量的线程。
    • 最后,使用 worker.join() 等待所有工作线程结束。
    • 这样,析构函数确保所有任务都已完成并且没有正在运行的工作线程。
  3. Enqueue 函数模板:

    • Enqueue 函数接受一个可调用对象 task,将其添加到任务队列中以供工作线程执行。
    • 首先,通过创建一个 std::unique_lock 对象 lock 来获取互斥锁,以确保对任务队列的访问是独占的。
    • 然后,使用 tasks.emplace(std::forward<F>(task)) 将任务添加到队列中。这里使用了 std::forward 来完美转发 task 参数,以避免不必要的拷贝或移动操作。
    • 最后,通过调用 condition.notify_one() 来通知一个正在等待任务的工作线程。
  4. 示例任务函数 TaskFunction

    • 这是一个简单的示例任务函数,它接受一个整数参数 taskId,并在控制台上打印任务执行的信息。
    • 在任务函数中,首先打印任务的执行信息,包括任务 ID 和当前线程的 ID。
    • 然后,使用 std::this_thread::sleep_for 模拟任务执行的耗时。
    • 最后,打印任务完成的信息。
  5. main 函数:

    • 在 main 函数中,首先创建了一个 ThreadPool 对象 pool,其中包含 4 个工作线程。
    • 然后,使用一个循环向线程池中添加 8 个任务,每个任务都是调用 TaskFunction 的 lambda 函数。
    • 在添加完所有任务后,通过调用 std::this_thread::sleep_for 等待一段时间,以确保所有任务完成。
    • 最后,返回 0 结束程序。
#include <iostream>
#include <vector>
#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <functional>

class ThreadPool {
public:
    ThreadPool(size_t numThreads) : stop(false) {
        for (size_t i = 0; i < numThreads; ++i) {
            workers.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();
                    }
                    task(); // 执行任务
                }
            });
        }
    }

    ~ThreadPool() {
        {
            std::unique_lock<std::mutex> lock(queueMutex);
            stop = true; // 设置停止信号
        }
        condition.notify_all(); // 唤醒所有线程
        for (std::thread& worker : workers) {
            worker.join(); // 等待线程结束
        }
    }

    template<class F>
    void Enqueue(F&& task) {
        {
            std::unique_lock<std::mutex> lock(queueMutex);
            tasks.emplace(std::forward<F>(task)); // 添加任务到队列
        }
        condition.notify_one(); // 唤醒一个线程执行任务
    }

private:
    std::vector<std::thread> workers; // 线程池中的工作线程
    std::queue<std::function<void()>> tasks; // 任务队列

    std::mutex queueMutex; // 互斥量,保护任务队列的访问
    std::condition_variable condition; // 条件变量,用于线程等待和唤醒
    bool stop; // 停止信号
};

// 示例任务函数
void TaskFunction(int taskId) {
    std::cout << "正在执行任务 " << taskId << ",线程ID:" << std::this_thread::get_id() << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::cout << "任务 " << taskId << " 完成" << std::endl;
}

int main() {
    ThreadPool pool(4);

    // 向线程池中添加任务
    for (int i = 0; i < 8; ++i) {
        pool.Enqueue([i] { TaskFunction(i); });
    }

    // 等待所有任务完成
    std::this_thread::sleep_for(std::chrono::seconds(5));

    return 0;
}

-------------------------------------------------分为cpp文件和头文件-------------------------------------------------

ThreadPool.h

#pragma once

#include <iostream>
#include <vector>
#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <functional>

class ThreadPool {
public:
    ThreadPool(size_t numThreads);
    ~ThreadPool();

    template<class F>
    void Enqueue(F&& task);

private:
    std::vector<std::thread> workers;
    std::queue<std::function<void()>> tasks;

    std::mutex queueMutex;
    std::condition_variable condition;
    bool stop;
};

ThreadPool.cpp

#include "ThreadPool.h"
#include <fstream>
#include <sstream>
#include <iomanip>

ThreadPool::ThreadPool(size_t numThreads) : stop(false) {
    workers.reserve(numThreads);
    for (size_t i = 0; i < numThreads; ++i)
    {
        workers.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();
                }
                task();
            }});
    }
}

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

template<class F>
void ThreadPool::Enqueue(F&& task) {
    {
        std::unique_lock<std::mutex> lock(queueMutex);
        tasks.emplace(std::forward<F>(task));
    }
    condition.notify_one();
}

void WriteDataInFile(int taskId, int fileSize)
{
    std::cout << "Executing task " << taskId << " on thread " << std::this_thread::get_id() << std::endl;

    std::ostringstream oss;

    oss << "D:/CPHY/PCIE_CPHY_Tool/bmp_header/bmp_header/outputFile/z" << std::setw(6) << std::setfill('0') << taskId << ".txt";
    const std::string filename = oss.str();

    // 创建输出文件流
    std::ofstream file(filename, std::ios::binary);
    if (!file) {
        std::cerr << "无法打开文件 " << filename << " 进行写入." << std::endl;
        return;
    }

    // 定义填充数据
    const char fillData = 'A';

    // 写入数据直到文件大小达到目标大小
    int bytesWritten = 0;
    while (bytesWritten < fileSize) {
        // 计算当前写入块的大小
        int blockSize = std::min(fileSize - bytesWritten, 4096);

        // 创建填充块
        std::string block(blockSize, fillData);

        // 写入填充块到文件
        file.write(block.data(), block.size());

        // 更新已写入的字节数
        bytesWritten += blockSize;
    }

    // 关闭文件流
    file.close();

    std::cout << "文件保存成功: " << filename << std::endl;
    std::cout << "文件大小: " << bytesWritten / (1024 * 1024) << " MB" << std::endl;
    std::cout << "Task " << taskId << " completed" << std::endl;
}

int main() {
    ThreadPool pool(8);
    int dataSize = 1 * 1024 * 1024;

    // 向线程池中添加任务
    for (int i = 0; i < 33; ++i) {
        pool.Enqueue([i, dataSize] { WriteDataInFile(i, dataSize); });
    }

    // 等待所有任务完成
    std::this_thread::sleep_for(std::chrono::seconds(5));

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值