使用现代化C++实现线程池
完整代码
class ThreadPool {
std::atomic<bool> shutdown_;
BlockingQueue<std::function<void()> > queue_;
std::vector<std::thread> threads_;
std::mutex mutex_;
std::condition_variable cv_;
// 待线程池执行的任务仿函数封装类
class Worker {
ThreadPool *pool_;
public:
Worker() = delete;
explicit Worker(ThreadPool *pool) : pool_(pool) {}
void operator()() const{
while (!pool_->shutdown_) {
std::unique_lock lock(pool_->mutex_);
pool_->cv_.wait(lock, [this] {
return !pool_->queue_.empty();
});
auto func = pool_->queue_.pop();
lock.unlock();
func();
}
}
};
public:
// 默认线程数为 CPU 核数的两倍
ThreadPool() : ThreadPool(std::thread::hardware_concurrency() * 2) {}
explicit ThreadPool(size_t nThreads) : shutdown_(false), threads_(nThreads > 0 ? nThreads : 8) {
for (auto &thread: threads_) {
thread = std::thread(Worker(this));
}
}
// 删除拷贝构造和拷贝赋值函数,确保任务有且只有一份
ThreadPool(const ThreadPool &) = delete;
ThreadPool &operator=(const ThreadPool &) = delete;
[[maybe_unused]]
void shutdown() {
shutdown_ = true;
cv_.notify_all();
for (auto &thread: threads_) {
if (thread.joinable()) {
thread.join();
}
}
}
// 提交要由线程池异步执行的函数
// C++17之后,不建议使用decltype(f(args...))和std::result_of来推导函数返回值类型,建议使用std::invoke_result
template<typename F, typename... Args>
auto submit(F &&f, Args &&... args) -> std::future<std::invoke_result_t<F, Args...>> {
// 创建一个准备执行的函数对象
auto func = std::bind(std::forward<F>(f), std::forward<Args>(args)...);
// 将其封装到共享的智能指针中,以便复制和传递
auto taskPtr = std::make_shared<std::packaged_task<std::invoke_result_t<F, Args...>()> >(func);
// 将封装的任务包装到 std::function<void()> 中
const std::function<void()> wrapperFunc = [taskPtr] {
(*taskPtr)();
};
// 将包装后的通用函数添加到队列中
queue_.push(wrapperFunc);
// 唤醒一个正在等待的线程
cv_.notify_one();
// 返回future
return taskPtr->get_future();
}
};
本文链接:
/archives/X0EAQLUK
版权声明:
本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自
Liccsu's blog!
喜欢就支持一下吧
打赏
微信