我正在编码一个物理模拟,主要由一个数组上数百亿次重复操作的中心循环组成。这些操作独立于其他操作(实际上阵列实际上是沿途更改),因此我正在考虑并行化我的代码,因为我可以在我的实验室中运行4或8核计算机。 这是我第一次做同样的事情,我被建议看看openmp。我已经开始使用它编写一些玩具程序,但我真的不确定它是如何工作的,文档对我来说非常神秘。例如,以下代码:
int a = 0;
#pragma omp parallel
{
a++;
}
cout << a << endl;
在我的计算机上启动(4核CPU)有时给我4次,其他时间为3或2.这是因为它不等待所有核心执行指令吗?因为我确实需要知道在我的案例中完成了多少次迭代。考虑到我最终想要的东西,我应该寻找除了openmp以外的其他东西吗?
答案 0 :(得分:0)
当同时写入共享变量(代码中为a
)时,您会遇到数据竞争。要避免不同的线程“同时”写入,您必须使用原子赋值或使用互斥锁保护赋值(=互斥)。在OpenMP中,后者通过关键区域
int a = 0;
#pragma omp parallel
{
#pragma omp critical
{
a++;
}
}
cout << a << endl;
(当然,这个特殊的程序没有并行执行任何操作,因此比执行相同操作的序列程序要慢。)
有关详细信息,请阅读openMP文档!但是,我建议你不使用OpenMP,如果你使用的是C ++,则建议使用TBB。它更加灵活。
答案 1 :(得分:0)
您所看到的是race condition的典型示例。四个线程试图增加变量a
,他们正在为它而战。有些'输了'而且他们无法增加,所以你看到的结果低于4.
a++
命令实际上是一组三个指令:从内存中读取a
并将其放入寄存器中,递增寄存器中的值,然后将值重新放入记忆。如果线程1在线程2读取之后但在线程2将新值写回a
之前读取a
的值,则将覆盖thread2的增量操作。使用#omp critical
是一种确保所有读取/递增/写入操作不会被另一个线程中断的方法。
如果需要并行化迭代,可以使用omp parallel for
来增加数组中的所有元素。
典型用途:
#pragma omp parallel for
for (i = 0; i < N; i++)
a[i]++;