1. 前言
C++语言一直是并行计算的佼佼者,其拥有许多库和工具可用于高效的并行计算,如OpenMP, boost, TBB等。本文将为大家讲解如何使用C++进行高效的并行计算。
2. 并行编程基础
2.1 多线程概念
多线程是并行编程的一种重要形式,它是指一个进程同时运行多个线程。多线程执行不同的代码路径,同时访问不同的内存地址。在C++中,可以用std::thread来创建线程。下面是示例代码:
#include <thread>
#include <iostream>
void threadFunc() {
std::cout << "Hello, Thread!" << std::endl;
}
int main() {
std::thread t(threadFunc);
t.join(); //等待线程t结束
return 0;
}
在上面例子中,我们使用std::thread创建了一个线程t,它的执行路径是threadFunc函数。t.join()等待线程t结束,保证函数不会在线程t结束之前退出。
2.2 多线程间的通信
在并行编程中,不同的线程之间需要进行信息的交换,以完成数据的共享和协作工作。在C++中,可以用std::mutex和std::condition_variable来保证线程之间的同步和通信。下面是示例代码:
#include <thread>
#include <iostream>
#include <mutex>
#include <condition_variable>
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
void threadFunc() {
std::unique_lock<std::mutex> lk(mtx);
cv.wait(lk, [&]{return ready;}); //等待条件变量ready
std::cout << "Hello, Thread!" << std::endl;
}
int main() {
std::thread t(threadFunc);
{
std::lock_guard<std::mutex> lk(mtx);
ready = true;
}
cv.notify_one(); //通知等待线程
t.join();
return 0;
}
在上面例子中,我们通过std::unique_lock和std::lock_guard来保证了线程之间的互斥访问。通过std::condition_variable实现了线程之间的协作,等待条件变量的值ready为true时,线程才会继续执行。cv.notify_one()可以唤醒等待线程。
3. OpenMP并行编程
3.1 OpenMP概述
OpenMP是一个基于共享内存架构的并行编程接口,它提供了一种简单的方式来写并行程序。OpenMP的特点是便于在现有的串行代码中插入并行指令,加速程序运行。在C++中,可以用#pragma omp来引入OpenMP的指令。
3.2 OpenMP指令
下面我们来介绍一些常见的OpenMP指令。
3.2.1 基本指令
OpenMP中,最常用的指令是#pragma omp parallel,它将代码块并行化。下面是示例代码:
#include <iostream>
#include <omp.h>
int main() {
#pragma omp parallel
{
std::cout << "Hello, OpenMP!" << std::endl;
}
return 0;
}
在上面例子中,我们使用#pragma omp parallel将代码块并行化,omp.h提供了OpenMP相关的头文件。在并行块中,每个线程将执行代码块中的语句。
3.2.2 共享变量
在OpenMP中,需要显式声明shared关键字来告诉编译器哪些变量是共享的,哪些变量是私有的。下面是示例代码:
#include <iostream>
#include <omp.h>
int main() {
int sum = 0;
#pragma omp parallel shared(sum)
{
int tid = omp_get_thread_num();
sum += tid;
}
std::cout << "sum=" << sum << std::endl;
return 0;
}
在上面例子中,我们使用omp_get_thread_num函数获取线程的编号。由于sum是共享的,所以每个线程都可以读写它,需要注意同步问题。
3.2.3 计时指令
在OpenMP中,可以使用omp_get_wtime函数来获取程序运行时间。下面是示例代码:
#include <iostream>
#include <omp.h>
int main() {
double t1 = omp_get_wtime();
#pragma omp parallel
{
std::cout << "Hello, OpenMP!" << std::endl;
}
double t2 = omp_get_wtime();
std::cout << "time=" << t2 - t1 << std::endl;
return 0;
}
4. C++11并行编程
4.1 C++11线程库
C++11标准增加了线程库,使得C++成为一个完整的并行编程语言。线程库中,std::thread是最基本的类,可以用来创建线程。
#include <iostream>
#include <thread>
void threadFunc() {
std::cout << "Hello, C++11!" << std::endl;
}
int main() {
std::thread t(threadFunc);
t.join();
return 0;
}
4.2 C++11并发编程
C++11新增了std::atomic和std::mutex,使得并行编程更加简单和安全。
4.2.1 std::atomic
std::atomic类是一个线程安全的类型, 可以保证原子性操作。std::atomic支持的操作包括赋值、加、减、位运算、比较等。
#include <iostream>
#include <atomic>
#include <thread>
std::atomic<int> sum(0);
void threadFunc(int n) {
sum += n;
}
int main() {
std::thread t1(threadFunc, 1);
std::thread t2(threadFunc, 2);
t1.join();
t2.join();
std::cout << "sum=" << sum << std::endl;
return 0;
}
4.2.2 std::mutex
std::mutex是一个互斥量,用于保护共享资源。在访问共享资源的时候,需要先获取锁,操作完毕后再释放锁。
#include <iostream>
#include <mutex>
#include <thread>
std::mutex mtx;
int sum = 0;
void threadFunc(int n) {
mtx.lock();
sum += n;
mtx.unlock();
}
int main() {
std::thread t1(threadFunc, 1);
std::thread t2(threadFunc, 2);
t1.join();
t2.join();
std::cout << "sum=" << sum << std::endl;
return 0;
}
5. 总结
本文从多线程基础、OpenMP并行编程、C++11并行编程三个方面详细讲解了如何使用C++进行高效的并行计算,大家可以根据实际情况选择不同的方式进行应用。希望本文对大家有所帮助!