网络建设方式seo工资水平
目录
- 多线程与线程池
- 线程池的核心成员
- 线程池案例
- 1 运行环境以及目录
- 2 `ThreadPool.h`
- 3 `ThreadPool.cpp`
- 4 main.cpp
- 5、`CMakeLists.txt`
- 7、运行与打印
多线程与线程池
- 多线程:一种并发执行的技术,它允许在同一进程中同时执行多个线程。每个线程可以执行程序中的一部分代码,从而提高程序的执行效率。
- 线程池:一种设计模式,用于管理和复用线程。线程池维护着多个线程,等待监督管理者分配可并行执行的任务。这样避免了在短时间内创建和销毁线程的代价。
线程池的核心成员
1、任务队列,任务队列中存放需要线程执行的任务;
2、互斥锁,由于任务队列中是临界资源,被多个线程访问,需要互斥锁保证安全性;
3、条件变量,当任务队列不为空的时候或者需要停止线程池运行时唤醒线程;
4、工作线程,负责不断从任务队列中取出任务并执行。
5、线程池是否停止工作的标志;
运行逻辑如图所示:
线程池案例
1 运行环境以及目录
环境:Windows、Vscode、C++11
文件目录:
|—ThreadPool
|—main.cpp
|—ThreadPool.cpp
|—ThreadPool.h
|—CMakeLists.txt
2 ThreadPool.h
#define THREADPOOL_H#include <vector>
#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <functional> // std::function 提供了一种更通用的函数绑定和调用机制class ThreadPool{public:ThreadPool(size_t numWorkers, size_t maxTasks);~ThreadPool();void pushTask(std::function<void()> task); // 添加任务void waitAll(); // 等待所有任务完成private:void workerLoop(); // 工作线程的循环std::vector<std::thread> m_workers; // 工作线程std::queue<std::function<void()>> m_tasks; // 任务队列std::mutex m_mutex;std::mutex m_print_mutex;std::condition_variable m_cond;std::condition_variable m_completionCond;bool m_stop = false; // 线程池终止标志size_t m_maxTasks; // 最大任务数size_t m_activeTasks = 0; // 正在执行的任务数
};#endif
3 ThreadPool.cpp
#include "ThreadPool.h"
#include <iostream>// 线程池构造函数
ThreadPool::ThreadPool(size_t numWorkers, size_t maxTasks): m_maxTasks(maxTasks) {for(size_t i = 0; i< numWorkers; ++i){m_workers.emplace_back(&ThreadPool::workerLoop, this); // 创建工作线程并绑定到workerLoop函数上// 构造函数启动线程,但线程不会立刻执行,启动存在延迟,需要等待线程执行完才会输出// {// std::lock_guard<std::mutex> lock(m_print_mutex); // 加锁,确保输出的顺序// std::cout << "Thread " << i << " created." << "\tThread ID:"<< m_workers[i].get_id() << std::endl; // 输出线程创建信息// }}
}// 线程池析构函数
ThreadPool::~ThreadPool(){{std::unique_lock<std::mutex> lock(m_mutex); // 加锁m_stop = true; // 设置终止标志}m_cond.notify_all(); // 通知所有等待的线程for(auto &worker : m_workers){ // 等待所有工作线程结束if(worker.joinable()){worker.join(); // 等待线程结束}}
}// 向任务队列添加任务
void ThreadPool::pushTask(std::function<void()>task){std::unique_lock<std::mutex> lock(m_mutex); // 加锁m_cond.wait(lock, [this](){ return m_tasks.size() < m_maxTasks; }); // 等待任务队列有空位m_tasks.emplace(std::move(task)); // 添加任务到队列m_cond.notify_one(); // 通知一个等待的线程
}// 线程循环函数
void ThreadPool::workerLoop(){while(true){std::function<void()> task; // 定义一个任务函数{std::unique_lock<std::mutex> lock(m_mutex); // 加锁m_cond.wait(lock, [this]{ return m_stop || !m_tasks.empty(); }); // 等待任务队列有任务或者线程池终止if(m_stop && m_tasks.empty()) return; // 如果线程池终止且任务队列为空,退出线程task = std::move(m_tasks.front()); // 获取任务,.front()返回队列的第一个元素的引用m_tasks.pop(); // 从队列中移除任务,.pop()移除队列的第一个元素m_activeTasks++; // 增加正在执行的任务数}task(); // 执行任务{std::unique_lock<std::mutex> lock(m_mutex); // 加锁m_activeTasks--; // 减少正在执行的任务数if(m_activeTasks == 0){ // 如果所有任务都执行完毕m_completionCond.notify_all(); // 通知所有等待的线程}// 当程序执行到该作用域的末尾时,lock对象会被销毁,自动释放互斥锁。}}
}// 等待所有任务完成
void ThreadPool::waitAll(){std::unique_lock<std::mutex> lock(m_mutex);m_completionCond.wait(lock, [this]{ return m_activeTasks == 0 && m_tasks.empty(); }); // 等待所有任务完成
}
4 main.cpp
#include "ThreadPool.h"
#include <iostream>
#include <chrono>
#include <mutex>std::mutex mtx; // 用于同步输出的互斥锁void exampleTask(int taskId){{std::lock_guard<std::mutex> lock(mtx); // 加锁,确保输出的顺序std::cout << "Task " << taskId << " started." << "\tThread ID is " << std::this_thread::get_id() << std::endl;}std::this_thread::sleep_for(std::chrono::seconds(1)); // 模拟任务执行时间{std::lock_guard<std::mutex> lock(mtx);std::cout << "Task " << taskId << " finished." << "\tThread ID is " << std::this_thread::get_id() << std::endl;}
}int main(){const size_t numThreads = 4; // 线程池中的线程数量const size_t numTasks = 10; // 任务数量ThreadPool pool(numThreads, numTasks); // 创建线程池// 向线程池添加任务for(int i = 0; i < numTasks; ++i){pool.pushTask(std::bind(exampleTask, i)); // 使用std::bind绑定任务函数和参数// pool.pushTask([i]{exampleTask(i);}); }// 等待所有任务完成pool.waitAll();std::cout << "All tasks completed." << std::endl;return 0;
}
5、CMakeLists.txt
cmake_minimum_required(VERSION 3.15)
project(ThreadPoolV2)# 设置C++标准
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)# 自动包含当前目录源文件
file(GLOB SOURCES CONFIGURE_DEPENDS"*.cpp""*.h"
)# 创建可执行目标
add_executable(threadpoolv2${SOURCES}
)# 多线程支持配置
if(CMAKE_CXX_COMPILE_ID MATCHES "GNU")# 针对MinGW的特殊设置set(THREADS_PREFER_PTHREAD_FLAG ON)find_package(Threads REQUIRED)target_link_libraries(threadpoolv2PRIVATEThreads::Threads-static # 静态链接标准库)
endif()
6、编译过程
mkdir build
cd build
cmake .. -G "MinGW Makefiles"
cmake --build .
如果运行成功,则大概出现以下打印内容
[ 33%] Building CXX object CMakeFiles/threadpool.dir/ThreadPool.cpp.obj
[ 66%] Building CXX object CMakeFiles/threadpool.dir/main.cpp.obj
[100%] Linking CXX executable threadpool.exe
[100%] Built target threadpool
7、运行与打印
./threadpool // 运行可执行程序// 运行正确则打印如下内容:
Task 0 started. Thread ID is 5
Task 1 started. Thread ID is 3
Task 2 started. Thread ID is 2
Task 3 started. Thread ID is 4
Task 2 finished. Thread ID is 2
Task 4 started. Thread ID is 2
Task 1 finished. Thread ID is 3
Task 5 started. Thread ID is 3
Task 0 finished. Thread ID is 5
Task 3 finished. Thread ID is 4
Task 7 started. Thread ID is 4
Task 6 started. Thread ID is 5
Task 4 finished. Thread ID is 2
Task 8 started. Thread ID is 2
Task 7 finished. Thread ID is 4
Task 0 started. Thread ID is 5
Task 1 started. Thread ID is 3
Task 2 started. Thread ID is 2
Task 3 started. Thread ID is 4
Task 2 finished. Thread ID is 2
Task 4 started. Thread ID is 2
Task 1 finished. Thread ID is 3
Task 5 started. Thread ID is 3
Task 0 finished. Thread ID is 5
Task 3 finished. Thread ID is 4
Task 7 started. Thread ID is 4
Task 6 started. Thread ID is 5
Task 4 finished. Thread ID is 2
Task 8 started. Thread ID is 2
Task 7 finished. Thread ID is 4
Task 1 started. Thread ID is 3
Task 2 started. Thread ID is 2
Task 3 started. Thread ID is 4
Task 2 finished. Thread ID is 2
Task 4 started. Thread ID is 2
Task 1 finished. Thread ID is 3
Task 5 started. Thread ID is 3
Task 0 finished. Thread ID is 5
Task 3 finished. Thread ID is 4
Task 7 started. Thread ID is 4
Task 6 started. Thread ID is 5
Task 4 finished. Thread ID is 2
Task 8 started. Thread ID is 2
Task 7 finished. Thread ID is 4
Task 1 finished. Thread ID is 3
Task 5 started. Thread ID is 3
Task 0 finished. Thread ID is 5
Task 3 finished. Thread ID is 4
Task 7 started. Thread ID is 4
Task 6 started. Thread ID is 5
Task 4 finished. Thread ID is 2
Task 8 started. Thread ID is 2
Task 7 finished. Thread ID is 4
Task 0 finished. Thread ID is 5
Task 3 finished. Thread ID is 4
Task 7 started. Thread ID is 4
Task 6 started. Thread ID is 5
Task 4 finished. Thread ID is 2
Task 8 started. Thread ID is 2
Task 7 finished. Thread ID is 4
Task 6 started. Thread ID is 5
Task 4 finished. Thread ID is 2
Task 8 started. Thread ID is 2
Task 7 finished. Thread ID is 4
Task 7 finished. Thread ID is 4
Task 9 started. Thread ID is 4
Task 6 finished. Thread ID is 5
Task 5 finished. Thread ID is 3
Task 8 finished. Thread ID is 2
Task 9 finished. Thread ID is 4
All tasks completed.