代码之家  ›  专栏  ›  技术社区  ›  Sebastian Mach

三重检查锁定?

  •  2
  • Sebastian Mach  · 技术社区  · 15 年前

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

    此遍历的灵感来源于第12页的模式 C++ and the Perils of Double-Checked Locking ,但尝试更便宜:

    (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 也将作为一个硬序列点,编译器和处理器将不被允许跨它们重新排序操作。

    编辑:

    (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 回复  |  直到 15 年前
        1
  •  3
  •   Vlad    15 年前

    看来你的模式不正确。考虑线程1执行到第一次之后的情况。 #pragma flush c ,控件将在第二秒之前收回 #布拉格齐平 . 现在第一个线程醒来,并重新创建子线程。