Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/132.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
三重检查锁定? 所以,我们知道,双检查锁是不工作的C++,至少不是以便携的方式。_C++_C_Multicore_Double Checked Locking_Lazy Initialization - Fatal编程技术网

三重检查锁定? 所以,我们知道,双检查锁是不工作的C++,至少不是以便携的方式。

三重检查锁定? 所以,我们知道,双检查锁是不工作的C++,至少不是以便携的方式。,c++,c,multicore,double-checked-locking,lazy-initialization,C++,C,Multicore,Double Checked Locking,Lazy Initialization,我刚刚意识到我在一个懒惰的四叉树中有一个脆弱的实现,我将它用于地形光线跟踪器。因此,我试图找到一种方法,仍然以安全的方式使用延迟初始化,因为我不想将内存使用率提高四倍,并重新排序大部分已实现的算法 此遍历的灵感来源于的第12页上的模式,但尝试以更便宜的价格进行: (pseudo code!) struct Foo { bool childCreated[4]; Mutex mutex[4]; Foo child[4]; void traverse (...)

我刚刚意识到我在一个懒惰的四叉树中有一个脆弱的实现,我将它用于地形光线跟踪器。因此,我试图找到一种方法,仍然以安全的方式使用延迟初始化,因为我不想将内存使用率提高四倍,并重新排序大部分已实现的算法

此遍历的灵感来源于的第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答案(引入第三次刷新):

edit:Version 3,我不知何故发现这相当于Version 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执行到第一个代码> >然后控件切换到线程#2,该线程继续并创建一个
c
,控件在第二个
#pragma flush
之前被取回。现在第一个线程醒来,并重新创建子线程

编辑:抱歉,错误:它将无法获取锁


编辑2:不,仍然正确,因为该值不会在线程1中刷新

我添加了另一个修订。虽然我必须承认,这一天已经很长了,我已经慢慢摆脱了头脑风暴。我认为我们仍然需要在
create(c)
childCreated[c]=true,否则它们可能会被重新排序(线程#3可能会开始使用尚未创建的
c
)。在添加第三个版本时,我完全意识到:),但当我看到第三个版本时,它看起来太琐碎而不正确。喝更多的咖啡不再是一种选择,因为我已经对此饱和了:/你的修订版#3是否与你提到的PDF第12页的代码基本相同?我认为在输入函数和第一次检查之间存在障碍,但我的第一个障碍是在第一次检查之后。
(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;
            }
        }
    }
}