gpt4 book ai didi

c++ - parallel_for 中互斥锁的多线程替代方案

转载 作者:搜寻专家 更新时间:2023-10-31 00:54:29 31 4
gpt4 key购买 nike

我是 C++ 的新手,因此如果这是一个愚蠢的问题请原谅,但我没有在互联网上找到我正在寻找的很好的例子。

基本上,我使用 parallel_for 循环来查找 2D 数组中的最大值(以及其间的一系列其他操作)。首先,我什至不知道这是否是最佳方法,但鉴于此二维数组的长度,我认为拆分计算会更快。

我的代码:

vector<vector<double>> InterpU(1801, vector<double>(3601, 0));
Concurrency::parallel_for(0, 1801, [&](int i) {

long k = 0; long l = 0;
pair<long, long> Normalized;
double InterpPointsU[4][4];
double jRes;
double iRes = i * 0.1;
double RelativeY, RelativeX;
int p, q;

while (iRes >= (k + 1) * DeltaTheta) k++;
RelativeX = iRes / DeltaTheta - k;
for (long j = 0; j < 3600; j++)
{
jRes = j * 0.1;
while (jRes >= (l + 1) * DeltaPhi) l++;
RelativeY = jRes / DeltaPhi - l;
p = 0;
for (long m = k - 1; m < k + 3; m++)
{
q = 0;
for (long n = l - 1; n < l + 3; n++)
{
Normalized = Normalize(m, n, PointsTheta, PointsPhi);
InterpPointsU[p][q] = U[Normalized.first][Normalized.second];
q++;
}
p++;
}
InterpU[i][j] = bicubicInterpolate(InterpPointsU, RelativeX, RelativeY);
if (InterpU[i][j] > MaxU)
{
SharedDataLock.lock();
MaxU = InterpU[i][j];
SharedDataLock.unlock();
}
}
InterpU[i][3600] = InterpU[i][0];
});

你可以在这里看到我正在使用一个名为 SharedDataLockmutex 来保护访问同一资源的多个线程。 MaxU 是一个变量,它应该只包含 InterpU vector 的最大值。代码运行良好,但由于我遇到了速度性能问题,我开始研究 atomic 和其他一些东西。

有没有什么好的例子可以说明如何修改类似的代码以使其更快?

最佳答案

如 VTT 所述,您可以简单地找到每个线程的局部最大值,然后使用 combinable 合并它们:

Concurrency::combinable<double> CombinableMaxU;
Concurrency::parallel_for(0, 1801, [&](int i) {
...
CombinableMaxU.local() = std::max(CombinableMaxU.local(), InterpU[i][j]);
}
MaxU = std::max(MaxU, CombinableMaxU.combine(std::max<double>));

请注意,您当前的代码实际上是错误的(除非MaxU 是原子的),您在锁外读取了MaxU,而它可以由其他线程同时写入。通常,您不得读取同时写入的值,除非双方 都受到原子语义或锁和内存栅栏的保护。原因是变量访问很可能包含多个内存访问,具体取决于硬件支持的类型。

但在你的情况下,你甚至有一个经典的竞争条件:

MaxU == 1
Thread a | Thread b
InterpU[i][j] = 3 | InterpU[i][j] = 2
if (3 > MaxU) | if (2 > MaxU)
SharedDataLock.lock(); | SharedDataLock.lock();
(gets the lock) | (waiting for lock)
MaxU = 3 | ...
SharedDataLock.unlock(); | ...
... | (gets the lock)
| MaxU = 2
| SharedDataLock.unlock();
MaxU == 2

Locks are hard.

您还可以使用原子和 compute the maximum on that .不过,我猜1在循环内还是表现不佳2,在循环外不管你用原子还是锁都无所谓。

1:如有疑问,请勿猜测 - 测量!

2:仅仅因为某些东西是原子的并且受硬件支持,并不意味着它与访问本地数据一样高效。首先,原子指令通常比非原子指令的成本高得多,其次你必须处理非常糟糕的缓存效果,因为核心/缓存会争夺数据的所有权。虽然原子在许多情况下可能更优雅(恕我直言,这一次除外),但大多数情况下缩减速度更快。

关于c++ - parallel_for 中互斥锁的多线程替代方案,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45160438/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com