- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我有一个相当复杂的程序,在 MSVC 2010 Debug模式下使用 OpenMP 构建时会遇到奇怪的行为。我已尽力构建以下最小的工作示例(尽管它不是真正最小的),它缩小了真实程序的结构。
#include <vector>
#include <cassert>
// A class take points to the whole collection and a position Only allow access
// to the elements at that posiiton. It provide read-only access to query some
// information about the whole collection
class Element
{
public :
Element (int i, std::vector<double> *src) : i_(i), src_(src) {}
int i () const {return i_;}
int size () const {return src_->size();}
double src () const {return (*src_)[i_];}
double &src () {return (*src_)[i_];}
private :
const int i_;
std::vector<double> *const src_;
};
// A Base class for dispatch
template <typename Derived>
class Base
{
protected :
void eval (int dim, Element elem, double *res)
{
// Dispatch the call from Evaluation<Derived>
eval_dispatch(dim, elem, res, &Derived::eval); // Point (2)
}
private :
// Resolve to Derived non-static member eval(...)
template <typename D>
void eval_dispatch(int dim, Element elem, double *res,
void (D::*) (int, Element, double *))
{
#ifndef NDEBUG // Assert that this is a Derived object
assert((dynamic_cast<Derived *>(this)));
#endif
static_cast<Derived *>(this)->eval(dim, elem, res);
}
// Resolve to Derived static member eval(...)
void eval_dispatch(int dim, Element elem, double *res,
void (*) (int, Element, double *))
{
Derived::eval(dim, elem, res); // Point (3)
}
// Resolve to Base member eval(...), Derived has no this member but derived
// from Base
void eval_dispatch(int dim, Element elem, double *res,
void (Base::*) (int, Element, double *))
{
// Default behavior: do nothing
}
};
// A middle-man who provides the interface operator(), call Base::eval, and
// Base dispatch it to possible default behavior or Derived::eval
template <typename Derived>
class Evaluator : public Base<Derived>
{
public :
void operator() (int N , int dim, double *res)
{
std::vector<double> src(N);
for (int i = 0; i < N; ++i)
src[i] = i;
#pragma omp parallel for default(none) shared(N, dim, src, res)
for (int i = 0; i < N; ++i) {
assert(i < N);
double *r = res + i * dim;
Element elem(i, &src);
assert(elem.i() == i); // Point (1)
this->eval(dim, elem, r);
}
}
};
// Client code, who implements eval
class Implementation : public Evaluator<Implementation>
{
public :
static void eval (int dim, Element elem, double *r)
{
assert(elem.i() < elem.size()); // This is where the program fails Point (4)
for (int d = 0; d != dim; ++d)
r[d] = elem.src();
}
};
int main ()
{
const int N = 500000;
const int Dim = 2;
double *res = new double[N * Dim];
Implementation impl;
impl(N, Dim, res);
delete [] res;
return 0;
}
vector
等等 但是
Element
,
Base
,
Evaluator
和
Implementation
捕获真实程序的基本结构。在 Debug模式下构建并运行调试器时,断言在
Point (4)
处失败.
Point (1)
,本地
i
有值
371152
,这很好。变量
elem
没有出现在框架中,这有点奇怪。但由于
Point (1)
处的断言没有失败,我想这很好。
eval
来自
Evaluator
解析为其基类,因此
Point (2)
被执行。此时,调试器显示
elem
有
i_ = 499999
,不再是
i
用于创建
elem
在
Evaluator
在通过之前
按值 至
Base::eval
.下一点,它解析为
Point (3)
,这一次,
elem
有
i_ = 501682
,超出范围,这是调用定向到
Point (4)
时的值并且断言失败。
Element
对象按值传递,其成员的值发生变化。多次重新运行程序,会发生类似的行为,但并不总是可重现。在实际程序中,这个类被设计为类似于一个迭代器,它对粒子集合进行迭代。虽然它迭代的东西不像容器那样精确。但无论如何,关键是它足够小,可以有效地通过值传递。因此,客户端代码知道它有自己的
Element
拷贝。而不是一些引用或指针,只要他坚持
Element
就不需要担心线程安全(很多)的接口(interface),它只提供对整个集合的单个位置的写访问。
elem
创建于约
Point (1)
应该是循环体的局部。另外,在整个程序中,没有大于
N
的值。产生了,那么这些新的值(value)是从哪里来的呢?
elem.i_
elem
时更改按值传递,指针
elem.src_
不会随之改变。按值传递后具有相同的值(内存地址)
Visual Studio 10 Win64
目标,编译器标志似乎是
/DWIN32 /D_WINDOWS /W3 /Zm1000 /EHsc /GR /D_DEBUG /MDd /Zi /Ob0 /Od /RTC1
这是在 Property Pages-C/C++-Command Line 中找到的命令行
/Zi /nologo /W3 /WX- /Od /Ob0 /D "WIN32" /D "_WINDOWS" /D "_DEBUG" /D "CMAKE_INTDIR=\"Debug\"" /D "_MBCS" /Gm- /EHsc /RTC1 /MDd /GS /fp:precise /Zc:wchar_t /Zc:forScope /GR /openmp /Fp"TestOMP.dir\Debug\TestOMP.pch" /Fa"Debug" /Fo"TestOMP.dir\Debug\" /Fd"C:/Users/Yan Zhou/Dropbox/Build/TestOMP/build/Debug/TestOMP.pdb" /Gd /TP /errorReport:queue
最佳答案
显然,MSVC 中的 64 位 OpenMP 实现与未经优化编译的代码不兼容。
为了调试您的问题,我修改了您的代码以将迭代编号保存到 threadprivate
调用 this->eval()
之前的全局变量然后在Implementation::eval()
的开头加了一个check查看保存的迭代次数是否与 elem.i_
不同:
static int _iter;
#pragma omp threadprivate(_iter)
...
#pragma omp parallel for default(none) shared(N, dim, src, res)
for (int i = 0; i < N; ++i) {
assert(i < N);
double *r = res + i * dim;
Element elem(i, &src);
assert(elem.i() == i); // Point (1)
_iter = i; // Save the iteration number
this->eval(dim, elem, r);
}
}
...
...
static void eval (int dim, Element elem, double *r)
{
// Check for difference
if (elem.i() != _iter)
printf("[%d] _iter=%x != %x\n", omp_get_thread_num(), _iter, elem.i());
assert(elem.i() < elem.size()); // This is where the program fails Point (4)
for (int d = 0; d != dim; ++d)
r[d] = elem.src();
}
...
elem.i_
成为在不同线程中传递给
void eval_dispatch(int dim, Element elem, double *res, void (*) (int, Element, double *))
的值的糟糕混合.这种情况在每次运行中发生数百次,但您只能看到一次
elem.i_
的值。变得足够大以触发断言。有时会发生混合值没有超过容器的大小,然后代码在没有断言的情况下完成执行。此外,您在断言后的调试 session 期间看到的是 VS 调试器无法正确处理多线程代码:)
this->eval()
也不会发生这种情况。在临界区:
#pragma omp parallel for default(none) shared(N, dim, src, res)
for (int i = 0; i < N; ++i) {
...
#pragma omp critical
this->eval(dim, elem, r);
}
}
Element
的隐式复制构造函数类使用简单的按位复制(它甚至是内联的)并且所有操作都在堆栈上完成。
/openmp
的文档MSDN 中的选项没有说明可能来自“错误”优化级别的可能相互引用。这也可能是一个错误。如果可以访问,我应该使用另一个版本的 VS 进行测试。
this->eval(dim, elem, r);
elem
的临时拷贝创建并通过地址传递给
eval()
Windows x64 ABI 要求的方法。奇怪的事情来了:这个临时拷贝的位置不在实现并行区域的 funclet 的堆栈上(顺便说一下,MSVC 编译器将其称为
Evaluator$omp$1<Implementation>::operator()
),正如人们所期望的那样,而是将其地址作为funclet 的第一个参数。由于此参数在所有线程中都是一个且相同,这意味着进一步传递给
this->eval()
的临时拷贝实际上在所有线程之间共享,这很荒谬但仍然是正确的,因为人们可以很容易地观察到:
...
void eval (int dim, Element elem, double *res)
{
printf("[%d] In Base::eval() &elem = %p\n", omp_get_thread_num(), &elem);
// Dispatch the call from Evaluation<Derived>
eval_dispatch(dim, elem, res, &Derived::eval); // Point (2)
}
...
...
#pragma omp parallel for default(none) shared(N, dim, src, res)
for (int i = 0; i < N; ++i) {
...
Element elem(i, &src);
...
printf("[%d] In parallel region &elem = %p\n", omp_get_thread_num(), &elem);
this->eval(dim, elem, r);
}
}
...
[0] Parallel region &elem = 000000000030F348 (a)
[0] Base::eval() &elem = 000000000030F630
[0] Parallel region &elem = 000000000030F348 (a)
[0] Base::eval() &elem = 000000000030F630
[1] Parallel region &elem = 000000000292F9B8 (b)
[1] Base::eval() &elem = 000000000030F630 <---- !!
[1] Parallel region &elem = 000000000292F9B8 (b)
[1] Base::eval() &elem = 000000000030F630 <---- !!
elem
在执行并行区域的每个线程中具有不同的地址(点
(a)
和
(b)
)。但是请注意传递给
Base::eval()
的临时拷贝。在每个线程中具有相同的地址。我相信这是一个编译器错误,它使
Element
的隐式复制构造函数|使用共享变量。这可以通过查看传递给
Base::eval()
的地址轻松验证。 - 它位于
N
地址之间的某处和
src
,即在共享变量块中。对汇编源代码的进一步检查表明,临时位置的地址确实作为参数传递给了
_vcomp_fork()
。函数来自
vcomp100.dll
它实现了 OpenMP fork/join 模型的 fork 部分。
Base::eval()
,
Base::eval_dispatch()
, 和
Implementation::eval()
所有都被内联,因此没有
elem
的临时拷贝曾经做过,我发现的唯一解决方法是:
Element elem
论据
Base::eval()
引用:
void eval (int dim, Element& elem, double *res)
{
eval_dispatch(dim, elem, res, &Derived::eval); // Point (2)
}
elem
的本地拷贝在
Evaluator<Implementation>::operator()
中实现并行区域的 funclet 的堆栈中被传递而不是共享的临时拷贝。这进一步通过值作为另一个临时拷贝传递给
Base::eval_dispatch()
但它保留了正确的值,因为这个新的临时拷贝在
Base::eval()
的堆栈中。而不是在共享变量块中。
Element
提供显式复制构造函数:
Element (const Element& e) : i_(e.i_), src_(e.src_) {}
关于c++ - 复制对象时,带有 MSVC 2010 Debug 的 OpenMP 会生成奇怪的错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11479337/
我正在尝试使用以下 keytool 命令为我的应用程序生成 keystore : keytool -genkey -alias tomcat -keystore tomcat.keystore -ke
编辑:在西里尔正确解决问题后,我注意到只需将生成轴的函数放在用于生成标签的函数下面就可以解决问题。 我几乎读完了 O'Reilly 书中关于 D3.js 的教程,并在倒数第二页上制作了散点图,但是当添
虽然使用 GraphiQL 效果很好,但我的老板要求我实现一个用户界面,用户可以在其中通过 UI 元素(例如复选框、映射关系)检查呈现给他们的元素并获取数据,这样做将为该人生成 graphql 输入,
我尝试在 Netbean 6.8 中使用 ws-import 生成 Java 类。我想重新生成 jax-ws,因为在 ebay.api.paypalapi 包中发现了一个错误(我认为该错误是由于 Pa
我有一个 perl 脚本,它获取系统日期并将该日期写入文件名。 系统日期被分配给 TRH1 变量,然后它被设置为一个文件名。 $TRH1 =`date + %Y%m%d%H%M`; print "TR
我是 Haskell 的新手,需要帮助。我正在尝试构建一种必须具有某种唯一性的新数据类型,因此我决定使用 UUID 作为唯一标识符: data MyType = MyType { uuid ::
我制作了一个脚本,它可以根据 Mysql 数据库中的一些表生成 XML。 该脚本在 PHP 中运行。 public function getRawMaterials($apiKey, $format
所以这是我的项目中的一个问题。 In this task, we will use OpenSSL to generate digital signatures. Please prepare a f
我在 SAS LIFEREG 中有一个加速故障时间模型,我想绘制它。因为 SAS 在绘图方面非常糟糕,我想实际重新生成 R 中曲线的数据并将它们绘制在那里。 SAS 提出了一个尺度(在指数分布固定为
我正在为 Django 后端制作一个样板,并且我需要能够使它到达下一个下载它的人显然无法访问我的 secret key 的地方,或者拥有不同的 key 。我一直在研究一些选项,并在这个过程中进行了实验
我正在创建一个生成采购订单的应用程序。我可以根据用户输入的详细信息创建文本文件。我想生成一个看起来比普通文本文件好得多的 Excel。有没有可以在我的应用程序中使用的开源库? 最佳答案 目前还没有任何
我正在尝试使用 ScalaCheck 为 BST 创建一个 Gen,但是当我调用 .sample 方法时,它给了我 java.lang.NullPointerException。我哪里错了? seal
已关闭。此问题需要 debugging details 。目前不接受答案。 编辑问题以包含 desired behavior, a specific problem or error, and the
我尝试编写一些代码,例如(在verilog中): parameter N = 128; if (encoder_in[0] == 1) begin 23 binary_out = 1;
我正忙于在 Grails 项目中进行从 MySQL 到 Postgres 的相当复杂的数据迁移。 我正在使用 GORM 在 PostGres 中生成模式,然后执行 MySQL -> mysqldump
如何使用纯 XSLT 生成 UUID?基本上是寻找一种使用 XSLT 创建独特序列的方法。该序列可以是任意长度。 我正在使用 XSLT 2.0。 最佳答案 这是一个good example 。基本上,
我尝试安装.app文件,但是当我安装并单击“同步”(在iTunes中)时,我开始在设备上开始安装,然后停止,这是一个问题,我不知道在哪里,但我看到了我无法解决的奇怪的事情: 最佳答案 似乎您没有在Xc
自从我生成 JavaDocs 以来已经有一段时间了,我确信这些选项在过去 10 年左右的时间里已经得到了改进。 我能否得到一些有关生成器的建议,该生成器将输出类似于 .Net 文档结构的 JavaDo
我想学习如何生成 PDF,我不想使用任何第三方工具,我想自己用代码创建它。到目前为止,我所看到的唯一示例是我通过在第 3 方 dll 上打开反射器查看的代码,以查看发生了什么。不幸的是,到目前为止我看
我正在从 Epplus 库生成 excel 条形图。 这是我成功生成的。 我的 table 是这样的 Mumbai Delhi Financial D
我是一名优秀的程序员,十分优秀!