在C中仔细检查锁定模式问题

时间:2017-05-04 23:37:18

标签: c memory-barriers

正如所有研究过这一点的人,我已经阅读了论文http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf

我对在C结构上实现DCLP时的障碍有疑问。这是代码:

typedef struct _singleton_object {
    int x;
    int y;
} sobject;

static sobject *singleton_object = NULL;

sobject *get_singleton_instance()
{
    sobject *tmp = singleton_object;

    /* Insert barrier here - compiler or cpu specific or both? */
    if (tmp == NULL) {
        mutex_lock(&lock); /* assume lock is declared and initialized properly*/
        tmp = singleton_object;
        if (tmp == NULL) {
            tmp = (sobject *)malloc(sizeof(sobject)); /* assume malloc succeeds */
            tmp->x = 5;
            tmp->y = 7;

            /* Insert barrier here - compiler or cpu specific or both ?*/
            singleton_object = tmp;
        }
        mutex_unlock(&lock);
    }
    return tmp;
}

第一个问题与评论中一样:当论文描述插入障碍时,它是指编译器,CPU还是两者兼而有之?我假设两者。

我的第二个问题是:什么阻止编译器在代码中用singleton_object替换tmp?是什么迫使singleton_object加载到tmp中,这可能是在编译器生成的代码中的寄存器或堆栈中?如果编译器在每次引用tmp时实际加载到& singleton_object的寄存器并丢弃该值,该怎么办? 看起来下面引用的论文中的解决方案取决于我们使用局部变量的事实。如果编译器没有将指针变量中的值加载到局部变量tmp,我们又回到了论文中描述的原始问题。

我的第三个问题是:假设,编译器会将singleton_object的值本地复制到寄存器或堆栈中(即变量tmp),为什么我们需要第一个障碍?在函数的开头不应该重新排序tmp = singleton_object和if(tmp == NULL),因为在使用tmp写入依赖之后存在隐式读取。此外,即使我们在第一次加载到tmp时从CPU的缓存读取过时值,它也应该被读为NULL。如果它不是NULL,那么对象构造应该是完整的,因为构造它的线程/ CPU应该执行屏障,这确保了在singleton_object具有非NULL值之前,所有CPU都可以看到x和y的存储。 / p>

1 个答案:

答案 0 :(得分:0)

  1.   

    当论文描述插入障碍时,它只意味着编译器,CPU或两者兼而有之?

    这两个障碍应该是 CPU-barriers (这意味着编译器障碍)。

  2.   

    什么阻止编译器在代码中用tmp替换singleton_object

    转让后的障碍

    sobject *tmp = singleton_object;
    

    除其他外意味着(包括CPU和编译器):

    **屏障之前发出的所有读取访问权限应在屏障之前完成。

    正因如此,编译器不允许在障碍之后读取<{em> singleton_object变量而不是tmp

  3.   

    如果它(singleton_object)不是NULL,那么对象构造应该是完整的,因为构造它的线程/ CPU应该执行屏障,这确保了存储到x和{在y具有非NULL值之前,所有CPU都可以看到{1}}。

    您需要为实际使用执行障碍这些&#34;可见&#34;变量singleton_objectx。如果没有屏障,读取线程可能会使用陈旧的值。

    通常,不同线程之间的每次同步都需要某种“屏障”。在双方:读写。