-
24-09-2019 - |
题
因此,在此期间,我们知道双重检查锁定为是确实在C ++中没有工作,至少不能在便携式方式。
我只是意识到我有一个懒惰四叉树,我使用的地形射线追踪一个脆弱实现。所以,我试图找到一种方法,仍然使用延迟初始化以安全的方式,因为我不希望的实现算法四倍的内存使用和重新排序大的部分。
此遍历由图案 C ++和的危险的第12页上的启发双检锁定,但试图做更便宜:
(pseudo code!)
struct Foo {
bool childCreated[4];
Mutex mutex[4];
Foo child[4];
void traverse (...) {
...
if (!childCreated[c]) {
// get updated view
#pragma flush childCreated[c]
if (!childCreated[c]) {
ScopedLock sl (mutex[c]);
if (!childCreated[c]) {
create (c);
#pragma flush childCreated[c]
childCreated[c] = true;
}
}
}
}
}
假设#pragma flush
也将作为其中的编译器和处理器不会跨越它们被允许重新排序操作的硬序列点。
你看到了哪些问题?
修改版本2,试图考虑Vlads答案(引进第三齐平):
(pseudo code!)
struct Foo {
bool childCreated[4];
Mutex mutex[4];
Foo child[4];
void traverse (...) {
...
if (!childCreated[c]) {
// get updated view
#pragma flush childCreated[c]
if (!childCreated[c]) {
ScopedLock sl (mutex[c]);
#pragma flush childCreated[c]
if (!childCreated[c]) {
create (c);
#pragma flush childCreated[c]
childCreated[c] = true;
}
}
}
}
}
编辑:版本3,我莫名其妙地发现这个漂亮的相当于第2版,因为我没有使用儿童本身,而是一个基本标志的合法性进行检查,主要依靠内存屏障形成之间孩子和写入到该标志。
(pseudo code!)
struct Foo {
bool childCreated[4];
Mutex mutex[4];
Foo child[4];
void traverse (...) {
...
if (!childCreated[c]) {
ScopedLock sl (mutex[c]);
#pragma flush childCreated[c]
if (!childCreated[c]) {
create (c);
#pragma flush childCreated[c]
childCreated[c] = true;
}
}
}
}
解决方案
看来你的模式是不正确的。考虑当线#1执行第一#pragma flush
后为止。然后,控制切换到线#2,其推移,并创建一个c
,控制被取回只是第二#pragma flush
之前。现在,第一个线程被唤醒,并重新创建子。
编辑:对不起,错误:它将无法采取锁定
编辑2:无,仍然是正确的,因为该值将在线程#被不冲洗1
不隶属于 StackOverflow