当涉及到多线程编程时,代码的正确性和可靠性至关重要。下面是对代码的详细解释:
-
ThreadPool
类的构造函数:ThreadPool(size_t numThreads)
构造函数接受一个整数参数numThreads
,表示线程池应该包含的工作线程数量。- 使用一个循环来创建指定数量的工作线程。每个工作线程都是一个 lambda 函数,它会循环地从任务队列中获取任务并执行。
- 在 lambda 函数中,首先会等待任务队列非空或者收到停止信号的条件变量通知。这里使用
condition.wait(lock, [this] { return stop || !tasks.empty(); })
来等待条件满足。lock
是一个std::unique_lock
对象,它在等待期间自动释放互斥锁,以便其他线程可以访问任务队列。 - 如果收到停止信号并且任务队列为空,则工作线程退出循环,线程函数结束。
- 否则,从任务队列中获取一个任务,并执行该任务。
-
ThreadPool
类的析构函数:- 析构函数首先设置停止信号
stop
为true
,以通知所有工作线程停止执行任务。 - 然后,通过调用
condition.notify_all()
来唤醒所有等待条件变量的线程。 - 最后,使用
worker.join()
等待所有工作线程结束。 - 这样,析构函数确保所有任务都已完成并且没有正在运行的工作线程。
- 析构函数首先设置停止信号
-
Enqueue
函数模板:Enqueue
函数接受一个可调用对象task
,将其添加到任务队列中以供工作线程执行。- 首先,通过创建一个
std::unique_lock
对象lock
来获取互斥锁,以确保对任务队列的访问是独占的。 - 然后,使用
tasks.emplace(std::forward<F>(task))
将任务添加到队列中。这里使用了std::forward
来完美转发task
参数,以避免不必要的拷贝或移动操作。 - 最后,通过调用
condition.notify_one()
来通知一个正在等待任务的工作线程。
-
示例任务函数
TaskFunction
:- 这是一个简单的示例任务函数,它接受一个整数参数
taskId
,并在控制台上打印任务执行的信息。 - 在任务函数中,首先打印任务的执行信息,包括任务 ID 和当前线程的 ID。
- 然后,使用
std::this_thread::sleep_for
模拟任务执行的耗时。 - 最后,打印任务完成的信息。
- 这是一个简单的示例任务函数,它接受一个整数参数
-
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;
}