首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >正确使用compare_exchange_weak

正确使用compare_exchange_weak
EN

Stack Overflow用户
提问于 2015-11-12 13:32:23
回答 1查看 416关注 0票数 1
代码语言:javascript
复制
const int SIZE = 20; 
struct Node { Node* next; };

std::atomic<Node*> head (nullptr);
void push (void* p)
{
    Node* n = (Node*) p;
    n->next = head.load (); 
    while (!head.compare_exchange_weak (n->next, n));
}
void* pop ()
{
    Node* n = head.load (); 
    while (n &&
          !head.compare_exchange_weak (n, n->next));

    return n ? n : malloc (SIZE);
}

void thread_fn()
{
    std::array<char*, 1000> pointers;

    for (int i = 0; i < 1000; i++) pointers[i] = nullptr;

    for (int i = 0; i < 10000000; i++)
    {   
        int r = random() % 1000;

        if (pointers[r] != nullptr) // allocated earlier
        {   
            push (pointers[r]);
            pointers[r] = nullptr;
        }   
        else
        {   
            pointers[r] = (char*) pop (); // allocate

            // stamp the memory
            for (int i = 0; i < SIZE; i++)
                pointers[r][i] = 0xEF;
        }   
    }   
}


int main(int argc, char *argv[])
{
    int N = 8;

   std::vector<std::thread*> threads;
   threads.reserve (N);

   for (int i = 0; i < N; i++)
       threads.push_back (new std::thread (thread_fn));

   for (int i = 0; i < N; i++)
       threads[i]->join();
}

compare_exchange_weak的这种用法有什么问题?上面的代码使用clang++ (MacOSX) 5次中就有1次崩溃。

崩溃时的head.load()将具有“0xEFEFEFEFEEF”。pop就像malloc,而push就像是免费的。每个线程(8个线程)从head随机分配或释放内存

EN

回答 1

Stack Overflow用户

发布于 2015-11-30 03:53:43

它可能是一个很好的无锁分配器,但是出现了ABA-problem

A:假设某个thread1执行pop(),将head的当前值读入n变量,但紧接着线程被抢占,并发thread2执行完整的pop()调用,即从head读取相同的值并成功执行compare_exchange_weak

B:现在,nthread1中引用的对象不再属于该列表,可以由thread2修改。因此,n->next通常是垃圾:从它读取可以返回任何值。例如,它可以是0xEFEFEFEFEF,其中前5个字节是thread2写入的stamp (EF),最后3个字节仍然是来自nullptr的0。(Total value以小端字节序的方式进行数值解释)。看起来,由于head值已更改,thread1将使其compare_exchange_weak调用失败,但是...

A:Concurrent thread2 push()es导致指针返回列表。因此,thread1看到head的初始值,并成功执行compare_exchange_weak,这会将不正确的值写入head。列表已损坏。

请注意,这个问题不仅仅是可能的,其他线程可以修改n->next的内容。问题是n->next 的值不再与列表耦合。因此,即使它没有被并发地修改,它也会变得无效(对于替换head),例如,当其他线程从列表中取回2个元素,但push()只返回其中的第一个元素时。(因此n->next将指向第二个元素,该元素不再属于列表。)

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33665038

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档