【发布时间】:2017-01-14 19:03:53
【问题描述】:
Microsoft's documention of Parallel.For 包含以下方法:
static void MultiplyMatricesParallel(double[,] matA, double[,] matB, double[,] result)
{
int matACols = matA.GetLength(1);
int matBCols = matB.GetLength(1);
int matARows = matA.GetLength(0);
// A basic matrix multiplication.
// Parallelize the outer loop to partition the source array by rows.
Parallel.For(0, matARows, i =>
{
for (int j = 0; j < matBCols; j++)
{
double temp = 0;
for (int k = 0; k < matACols; k++)
{
temp += matA[i, k] * matB[k, j];
}
result[i, j] = temp;
}
}); // Parallel.For
}
在此方法中,可能有多个线程从matA 和matB 读取值,这两个值都是在调用线程上创建和初始化的,并且可能有多个线程将值写入result,稍后由调用方读取线。在传递给Parallel.For 的 lambda 中,数组读取和写入没有显式锁定。由于此示例来自 Microsoft,因此我假设它是线程安全的,但我试图了解幕后发生的事情以使其成为线程安全的。
根据我所阅读的内容和我在 SO 上提出的其他问题(例如 this one),据我所知,需要几个内存屏障才能使这一切正常工作。它们是:
- 创建和初始化
matA和matB后调用线程上的内存屏障, - 在从
matA和matB读取值之前,每个非调用线程上的内存屏障, - 将值写入
result后,每个非调用线程上的内存屏障,并且 - 在从
result读取值之前调用线程上的内存屏障。
我理解正确吗?
如果是这样,Parallel.For 会以某种方式完成所有这些吗?我去挖掘参考源,但在关注the code 时遇到了麻烦。我没有看到任何lock 块或MemoryBarrier 调用。
【问题讨论】:
-
我预计 Parallel.For() 在它的开头和结尾都有内存屏障,你看过Parallel.For() 的源代码吗?
-
@IanRingrose,是的,正如我在问题中提到并链接到的。我没有找到任何
MemoryBarrier调用或锁定块。 -
但是在它调用的方法中呢,我希望它位于任务系统的顶部,并且任务系统中的某处是任务开始和结束的内存屏障。
-
是的,我希望如此。尚未完全跟踪代码。
-
@HansPassant 我确实相信 MS 做对了,但是我编写的线程代码是错误的,并且当我必须自己做时,准确理解需要做的事情对我有帮助,更重要的是,帮助我准确了解我可以依靠 MS 为我做什么,以及在使用 Microsoft 的模式和库时我仍然需要实现什么锁定等。
标签: c# multithreading memory-barriers parallel.for