- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
double compute_inner_contraction_0( double* X, double* T, int n, int f, int m, int e, int No, int Nv )
{
double contraction_value = 0.0;
int l_begin = 0;
int l_end = m;
for ( int l = l_begin; l < l_end; l++ )
{
int k_begin = 0;
int k_end = l;
for ( int k = k_begin; k < k_end; k++ )
{
contraction_value += (-1)*X[n * Nv * No * No * No * No + e * No * No * No * No + m * No * No * No + l * No * No + l * No + k]*T[k * Nv + f];
}
}
return contraction_value;
}
void compute_contraction_0( double* X, double* T, int No, int Nv, double* ExEx_block , int nthd )
{
omp_set_dynamic(0);
omp_set_num_threads(nthd);
#pragma omp parallel for
for ( int n = 0; n < No; n++ )
{
int f_begin = 0;
int f_end = Nv;
for ( int f = f_begin; f < f_end; f++ )
{
int m_begin = 0;
int m_end = n;
for ( int m = m_begin; m < m_end; m++ )
{
int e_begin = 0;
int e_end = f;
for ( int e = e_begin; e < e_end; e++ )
{
ExEx_block[n * Nv * No * Nv + f * No * Nv + m * Nv + e] += compute_inner_contraction_0( X, T, n, f, m, e, No, Nv);
}
}
}
}
}
大家好,抱歉函数太长了。请不要担心内存泄漏的索引,因为它们已经过广泛测试。基本上它是将数组 X 和 T 中的数字相乘,然后将结果添加到另一个数组 ExEx_block。此代码将在多线程上运行,但与在一个线程上运行的结果(正确)相比,会给出非常错误的计算结果。能否请你帮忙?它被构建为一个共享库(具有许多其他类似的功能)并从 Python 包装器加载。操作系统为CentOS 6,编译器为gcc-4.4.7它是一个具有 480 GB DDR3 的四路至强 E5-4620 (Sandy-EP)(总共 32 个内核)服务器。不,Nv 只是计算中需要的整数。 nthd(线程数)通常只有 10 或 20。这些数组的大小可以达到 17 GB。非常感谢您的宝贵时间。
最佳答案
我已经分析了您的代码,您在更新 ExEx_block
时遇到了竞争条件。没有其他可能的方法可以得到错误的结果 [因为其他一切都只是读取数据]。
为了让我们达成共识,我已经解释了我所说的竞争条件。
我还为您的程序制作了一个经过清理和简化的版本,没有任何修复。但是,它为固定版本奠定了基础。
并且,第二个版本包含一些示例 omp
指令,我认为您需要(例如 omp private
和 omp atomic
)
请注意,我没有尝试编译这些示例,因此仅将它们视为引用。
在您的程序中,如果两个不同的线程尝试同时更新 ExEx_block[i]
,就会出现竞争条件。为了简化,让我们使用 int
标量代替(例如)target
。原理是一样的。
假设 target
的值为 5。我们有两个线程 Ta
和 Tb
。 Ta
想要执行 target += 3
而 Tb
想要执行 target += 7
。还假设每个线程分别有一个私有(private)变量ta
和tb
。
Ta
Action 实际上是三个操作:
ta = target;
ta += 3
target = ta;
同样适用于 Tb
:
tb = target;
tb += 7;
target = tb;
只要它们不相交,一切都很好,我们将 [最终] 获得 15 的 target
值。
但是,如果任何操作被穿插,我们可能会得到 8 或 12,而不是正确的值 15:
ta = target;
tb = target;
ta += 3;
target = ta;
tb += 7;
target = tb;
程序的简化版本。
请注意,我用括号对事物进行了分组,并使用了诸如 int No4 = No * No * No * No
之类的事物来简化方程式并使其更具可读性。不是严格要求,但它帮助我发现问题和解决方案。我试着小心点,但我很容易搞砸了一个分组。
double
compute_inner_contraction_0(double *X,double *T,int n,int f,int m,int e,
int No,int Nv)
{
double contraction_value = 0.0;
int l_begin = 0;
int l_end = m;
int No2 = No * No;
int No3 = No2 * No;
int No4 = No3 * No;
for (int l = l_begin; l < l_end; l++) {
int k_begin = 0;
int k_end = l;
for (int k = k_begin; k < k_end; k++) {
contraction_value += (-1) *
X[(n * Nv * No4) + (e * No4) + (m * No3) + (l * No2) +
(l * No) + k] * T[(k * Nv) + f];
}
}
return contraction_value;
}
void
compute_contraction_0(double *X,double *T,int No,int Nv,double *ExEx_block,
int nthd)
{
omp_set_dynamic(0);
omp_set_num_threads(nthd);
int NoNv = Nv * No;
int NoNv2 = NoNv * Nv;
#pragma omp parallel for
for (int n = 0; n < No; n++) {
int f_begin = 0;
int f_end = Nv;
int nx = n * NoNv2;
for (int f = f_begin; f < f_end; f++) {
int m_begin = 0;
int m_end = n;
int fx = f * NoNv;
for (int m = m_begin; m < m_end; m++) {
int e_begin = 0;
int e_end = f;
int mx = m * Nv;
int ax = nx + fx + mx;
for (int e = e_begin; e < e_end; e++) {
ExEx_block[ax + e] +=
compute_inner_contraction_0(X,T,n,f,m,e,No,Nv);
}
}
}
}
}
您需要采取哪些措施来防止竞争条件的示例。
为了提高效率,我将 e
循环拆分为两个循环。一种执行繁重的计算,另一种更新全局数组。这有助于最大限度地减少线程停顿,在繁重的计算阶段相互等待。 “锁定”更新阶段是一个简单快速的循环。
您需要一个使用 omp 的 private
指令的每线程本地数组,并且需要将 omp atomic
添加到更新 ExEx_block
的循环中.
警告:虽然我已经使用 pthreads
进行了大量多线程编程并且知道如何修复竞争条件等,但我对特定的等效 omp
指令。
因此,根据我对 omp 文档的阅读,以下是我对您需要什么的最佳猜测。所以,请......彻底检查文档,了解我在这里使用的指令。
double
compute_inner_contraction_0(double *X,double *T,int n,int f,int m,int e,
int No,int Nv)
{
double contraction_value = 0.0;
int l_begin = 0;
int l_end = m;
int No2 = No * No;
int No3 = No2 * No;
int No4 = No3 * No;
for (int l = l_begin; l < l_end; l++) {
int k_begin = 0;
int k_end = l;
for (int k = k_begin; k < k_end; k++) {
contraction_value += (-1) *
X[(n * Nv * No4) + (e * No4) + (m * No3) + (l * No2) +
(l * No) + k] * T[(k * Nv) + f];
}
}
return contraction_value;
}
void
compute_contraction_0(double *X,double *T,int No,int Nv,double *ExEx_block,
int nthd)
{
omp_set_dynamic(0);
omp_set_num_threads(nthd);
int NoNv = Nv * No;
int NoNv2 = NoNv * Nv;
// ExEx_local must be at least Nv:
// NOTE: placement here may be wrong
double ExEx_local[Nv];
#pragma omp parallel for private(ExEx_local)
for (int n = 0; n < No; n++) {
int f_begin = 0;
int f_end = Nv;
int nx = n * NoNv2;
for (int f = f_begin; f < f_end; f++) {
int m_begin = 0;
int m_end = n;
int fx = f * NoNv;
for (int m = m_begin; m < m_end; m++) {
int e_begin = 0;
int e_end = f;
int mx = m * Nv;
int ax = nx + fx + mx;
// separate computation from global update
for (int e = e_begin; e < e_end; e++) {
ExEx_local[e] =
compute_inner_contraction_0(X,T,n,f,m,e,No,Nv);
}
// now do global update
for (int e = e_begin; e < e_end; e++) {
#pragma omp atomic update
ExEx_block[ax + e] += ExEx_local[e];
}
}
}
}
}
关于c - 多个线程的 openmp for loop 错误结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39025282/
OpenMP 中的高斯消除。我是 openmp 的新手,想知道我是否在正确的地方使用了我的编译指示和屏障。我的 x 值每次都不同。他们应该是一样的吗?? #include int num; doub
给定一个示例函数(示例在下面给出),for 循环可以使用 OpenMP 并行化或使用矢量化进行矢量化(假设编译器执行矢量化)。 示例 void function(float* a, float* b,
OpenMP 中原子和关键之间有什么区别? 我能做到 #pragma omp atomic g_qCount++; 但这和不一样吗 #pragma omp critical g_qCount++; ?
我有一个关于如何在您考虑特定依赖关系图时生成 OpenMP 伪代码的问题。 所以假设我们有这个特定的图表: 解决方案可能是这样的: #pragma omp parallel {
我正在尝试使用 openmp 计算二维矩阵的平均值。这个二维矩阵实际上是一个图像。 我正在对数据进行线程分割。例如,如果我有 N线程比我处理行/N thread0 的行数, 等等。 我的问题是:我可以
我想统计测量与 OpenMP 并行化的程序的性能。我选择在执行并行算法的测试应用程序中编写循环 MAX_EXPERIMENTS次并将时间测量报告到文件中。 问题解决方案似乎比提取外部循环上方的并行编译
我找到了 Intel's performance suggestion on Xeon Phi关于 OpenMP 中的 Collapse 子句。 #pragma omp parallel for co
如何使用 OpenMP 并行化数组移位? 我尝试了一些方法,但在以下示例中没有得到任何准确的结果(该示例旋转 Carteira 对象数组的元素,用于排列算法): void rotaciona(int
我有一系列对几个独立函数的调用。 func1(arg); func2(arg); func3(arg); 我想并行执行它们,而不是串行执行它们。我目前正在使用 #pragma omp parallel
我正在尝试使用 openmp 任务来安排基本 jacobi2d 计算的平铺执行。在 jacobi2d 中,依赖于 A(i,j) 从 A(i, j) A(i-1, j) A(i+1, j) A(i, j
我在 3 天前开始使用 OpenMP。我想知道如何使用#pragma使每个内核运行一个线程。详细信息:- int ncores = omp_get_num_procs();for(i = 0; i <
我有一段代码(它是应用程序的一部分),我正在尝试使用 OpenMP 对其进行优化,正在尝试各种调度策略。就我而言,我注意到 schedule(RUNTIME)条款比其他条款有优势(我没有指定 chun
我有一个数字运算 C/C++ 应用程序。它基本上是不同数据集的主循环。我们可以使用 openmp 和 mpi 访问一个 100 节点的集群。我想加速应用程序,但我是 mpi 和 openmp 的绝对新
在 OpenMP 中使用ompsections时,线程会被分配到sections内的 block ,还是每个线程会被分配到每个section? 当nthreads == 3时: #pragma omp
我正在尝试在 cython 中使用 openmp。我需要在 cython 中做两件事: i) 在我的 cython 代码中使用 #pragma omp single{} 作用域。 ii) 使用#pra
我正在尝试通过将循环的每次迭代作为 OpenMP 部分来并行化 OpenMP 中基于范围的 for 循环。我想这样做: #pragma omp parallel sections { for ( au
我正在尝试在 cython 中使用 openmp。我需要在 cython 中做两件事: i) 在我的 cython 代码中使用 #pragma omp single{} 作用域。 ii) 使用#pra
我想编写一个代码转换器,它采用基于 OpenMP 的并行程序并在集群上运行它。 我该如何解决这个问题?我使用哪些库?如何为此设置小型集群? 我发现很难在 Internet 上找到有关集群计算的好 Ma
我是 OpenMP 的新手。我正在尝试为 for 循环使用多个内核,但出现此编译错误: “错误 C3016:'x':OpenMP 'for' 语句中的索引变量必须具有带符号的整数类型”。 我知道 Op
如果我使用 VS 2010 编译器从 Qt Creator 构建项目,我如何启用 OpenMP(从 Visual Studio 构建时,您只需启用该功能)谢谢 最佳答案 在 .pro 文件中尝试下一步
我是一名优秀的程序员,十分优秀!