在现代软件开发中,高效的并发和并行编程变得越来越重要。C++ 作为一门广泛使用的高级编程语言,其强大的性能和灵活性使得它在处理并发和并行任务时尤为出色。本文将探讨在 C++ 框架中实现高效并发和并行编程的最佳实践,帮助开发者充分利用多核处理器和硬件资源。
理解并发与并行的区别
在深入探讨具体的编程实践之前,理解并发(concurrency)和并行(parallelism)之间的区别是至关重要的。
并发
并发是指在同一时间段内处理多个任务。尽管这些任务并不一定是同时执行的,但它们可以交替进行,例如通过多线程实现任务切换。
并行
并行则是指同时执行多个任务,通常是利用多核处理器的能力。这里的任务是真正意义上的同时执行,例如在不同的 CPU 核心上运行。
使用C++标准库实现并发和并行编程
线程
在 C++11 及以后的版本中,std::thread
提供了创建和管理线程的简单方法。以下是一个创建并启动线程的示例代码:
#include <iostream>
#include <thread>
void print_message() {
std::cout << "Hello from thread" << std::endl;
}
int main() {
std::thread t(print_message);
t.join(); // 等待线程完成
return 0;
}
互斥锁
并发编程中常见的问题之一是资源竞争。C++ 提供了 std::mutex
互斥锁来避免竞争条件:
#include <iostream>
#include <thread>
#include <mutex>
std::mutex mtx;
void print_message(const std::string& message) {
std::lock_guard<std::mutex> lock(mtx);
std::cout << message << std::endl;
}
int main() {
std::thread t1(print_message, "Hello from thread 1");
std::thread t2(print_message, "Hello from thread 2");
t1.join();
t2.join();
return 0;
}
锁和条件变量
条件变量可以让线程等待某个条件。以下示例展示了如何使用 std::condition_variable
配合互斥锁实现同步:
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
void print_id(int id) {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, []{ return ready; });
std::cout << "Thread " << id << std::endl;
}
void set_ready() {
std::unique_lock<std::mutex> lock(mtx);
ready = true;
cv.notify_all();
}
int main() {
std::thread threads[10];
for (int i = 0; i < 10; ++i)
threads[i] = std::thread(print_id, i);
set_ready();
for (auto& t : threads)
t.join();
return 0;
}
任务并行化
任务并行化可以简化并行编程,C++17 引入了并行 STL 算法。以下示例展示了如何使用并行算法:
#include <iostream>
#include <vector>
#include <algorithm>
#include <execution>
int main() {
std::vector<int> v(1000000, 1);
// 使用并行版本的 reduce
int sum = std::reduce(std::execution::par, v.begin(), v.end());
std::cout << "Sum: " << sum << std::endl;
return 0;
}
选择合适的并发工具及技术
并不是所有的并发工具和技术在所有场景下都能高效工作,选择合适的工具是实现高效并发和并行程序的关键。
线程池
线程池可以避免频繁创建和销毁线程带来的开销。C++ 并库(Boost)提供了强大的线程池支持:
#include <boost/asio.hpp>
void task(int i) {
std::cout << "Task " << i << " executed" << std::endl;
}
int main() {
boost::asio::thread_pool pool(4);
for (int i = 0; i < 8; ++i) {
boost::asio::post(pool, std::bind(task, i));
}
pool.join();
return 0;
}
异步编程
异步编程可以提高 I/O 密集型任务的效率。C++11 引入了 std::future
和 std::async
来实现异步调用:
#include <iostream>
#include <future>
int async_task() {
std::this_thread::sleep_for(std::chrono::seconds(1));
return 10;
}
int main() {
std::future<int> result = std::async(std::launch::async, async_task);
std::cout << "Waiting for result..." << std::endl;
std::cout << "Result: " << result.get() << std::endl;
return 0;
}