为什么这种竞争条件仅在-O3且仅在某些看似等效的代码顺序下发生?

问题描述 投票:-1回答:1

我实现了一个不可变的哈希图和附带的STM容器,它受clojure的atom的启发,这类似于C ++的std::unique_ptr,因为它通过指针管理(但不一定拥有)另一个对象,可以传递和换出,并且只能减少托管对象的引用计数,而不能完全破坏它。当运行一些用-O3编译的测试代码时,我开始注意到错误的结果。

用于比较和交换的代码看起来像这样:

hashmap *update(stm *stm, update_callback cb, void *user_args)
{
    while (1) {
        lock(stm->mutex);
        hashmap *current = stm->reference;
        increment_ref_count(current); // Line 6
        unlock(stm->mutex);

        hashmap *aspirant = cb(current, user_args); // returns a new, thread local instance
        increment_ref_count(aspirant);

        // Position 1

        lock(stm->mutex);
        if (current == stm->reference) { // success, no modification while we were busy
            stm->reference = aspirant;
            increment_ref_count(aspirant); // stm now has a reference
            unlock(stm->mutex);

            // Position 2.1
            decrement_ref_count(current); // release reference acquired at line 6

            decrement_ref_count(current); // stm no longer has a reference
            return aspirant;

        } else { // reference was modified, loop and try again
            unlock(stm->mutex);

            // Position 2.2
            decrement_ref_count(current); // release reference acquired at line 6

            decrement_ref_count(aspirant); // ref_count now at zero, aspirant is free'd
        }
    }
}

increment_decrement_ref_count自动增加/减少哈希图的引用计数。如果由于递减导致计数下降到零,则hasmap将在不久后释放。

设计用于引用计数指针的STM容器的挑战主要是关于获取引用并递增计数器原子,这就是为什么我在这里使用锁的原因。

作为测试,我正在使用hashmap + STM来统计单词列表中的出现次数。

如果我运行此处发布的代码,则不会发生竞争情况。 现在出现我的问题:如果将decrement_ref_count(current); // for line 6if/else中移出,请远离Positions 2.1/2.2(在第二个锁定区域之后),然后将其放在Position 1(在第二个锁定区域之前) ),突然单词计数开始不正确,我也不知道为什么。

[我的论点是:a)在第二个关键区域中我不使用current,并且b)因此,在比较和交换之前还是之后释放引用都没有关系。] >

显然,我有解决该问题的方法/解决方案;只需离开decrement的位置即可,但我真的很想知道为什么会这样。

在“ Linux的Windows子系统”上编译为:gcc -Wall -Wcast-align -Wswitch-enum -Wswitch-default -Winit-self -pedantic -O3 -DNDEBUG -std=gnu11

我实现了一个不可变的哈希图和附带的STM容器,它受clojure原子的启发,也就是说,类似于C ++的std :: unique_ptr,因为它可以管理(但不一定是...

c optimization race-condition reference-counting
1个回答
0
投票
我发现了问题-甚至有一个“教训”。首先,让我重新发布代码的损坏版本,以便于讨论:
© www.soinside.com 2019 - 2024. All rights reserved.