在现代软件开发中,随着硬件性能的提升和多核处理器的普及,并发和多线程编程变得越来越重要。C++作为一种高级编程语言,提供了丰富的工具和框架来实现并发和多线程处理。本文将介绍在C++框架中常见的并发和多线程处理模式。
线程创建与管理
std::thread
C++11引入了标准库中的std::thread类,用于创建和管理线程。使用std::thread,我们可以创建新线程并指定其要执行的函数或可调用对象。
#include <iostream>
#include <thread>
void foo() {
std::cout << "Running in a separate thread" << std::endl;
}
int main() {
std::thread t(foo);
t.join(); // 等待线程t执行完毕
return 0;
}
在上述代码中,我们创建了一个新线程t来执行函数foo。主线程通过调用join函数等待新线程执行完毕。
线程池
线程池是一种预先创建的线程集合,可以复用线程来处理多个任务,从而避免频繁创建和销毁线程带来的开销。Boost库提供了线程池的实现,也有第三方库如ThreadPool。
#include <iostream>
#include <vector>
#include <thread>
#include <queue>
#include <functional>
#include <condition_variable>
class ThreadPool {
public:
ThreadPool(size_t threads);
~ThreadPool();
template <class F, class... Args>
auto enqueue(F&& f, Args&&... args)
-> std::future<typename std::result_of<F(Args...)>::type>;
private:
// 处理线程池中的任务
std::vector<std::thread> workers;
// 存储任务的队列
std::queue<std::function<void()>> tasks;
// 同步机制
std::mutex queue_mutex;
std::condition_variable condition;
bool stop;
};
inline ThreadPool::ThreadPool(size_t threads)
: stop(false) {
for (size_t i = 0; i < threads; ++i)
workers.emplace_back(
[this] {
for (;;) {
std::function<void()> task;
{
std::unique_lock<std::mutex> lock(this->queue_mutex);
this->condition.wait(lock,
[this] { return this->stop || !this->tasks.empty(); });
if (this->stop && this->tasks.empty())
return;
task = std::move(this->tasks.front());
this->tasks.pop();
}
task();
}
}
);
}
template <class F, class... Args>
auto ThreadPool::enqueue(F&& f, Args&&... args)
-> std::future<typename std::result_of<F(Args...)>::type>
{
using return_type = typename std::result_of<F(Args...)>::type;
auto task = std::make_shared<std::packaged_task<return_type()>>(
std::bind(std::forward<F>(f), std::forward<Args>(args)...)
);
std::future<return_type> res = task->get_future();
{
std::unique_lock<std::mutex> lock(queue_mutex);
if (stop)
throw std::runtime_error("enqueue on stopped ThreadPool");
tasks.emplace([task](){ (*task)(); });
}
condition.notify_one();
return res;
}
inline ThreadPool::~ThreadPool() {
{
std::unique_lock<std::mutex> lock(queue_mutex);
stop = true;
}
condition.notify_all();
for (std::thread &worker: workers)
worker.join();
}
上面的代码展示了一个基本的线程池实现。ThreadPool类管理了一组工作线程和一个任务队列,支持任务的异步提交。
任务调度与同步
std::async
std::async是C++11中引入的另一个用于并发执行任务的工具。它允许我们启动一个异步任务,并返回一个std::future对象,该对象可以用于获取任务的返回值。
#include <iostream>
#include <future>
int foo() {
return 42;
}
int main() {
std::future<int> result = std::async(std::launch::async, foo);
std::cout << "The answer is " << result.get() << std::endl;
return 0;
}
在上述代码中,我们使用std::async启动了一个异步任务foo,并通过std::future对象result获取并打印了该任务的返回值。
同步原语
为了确保多线程访问共享资源时的一致性和正确性,我们需要使用同步原语,例如互斥量、条件变量和锁。
#include <iostream>
#include <thread>
#include <mutex>
std::mutex mtx;
void print_thread_id(int id) {
std::lock_guard<std::mutex> lock(mtx);
std::cout << "Thread ID: " << id << std::endl;
}
int main() {
std::thread t1(print_thread_id, 1);
std::thread t2(print_thread_id, 2);
t1.join();
t2.join();
return 0;
}
在上述代码中,我们使用std::mutex和std::lock_guard确保对标准输出的访问是线程安全的。
总结
C++提供了多种并发和多线程处理模式,包括直接使用std::thread创建和管理线程,使用线程池优化线程创建开销,以及使用std::async进行任务调度。同时,通过使用互斥量和条件变量等同步原语,我们可以确保多线程程序的正确性和一致性。合理运用这些模式,可以大幅提升程序的性能和响应速度。