代码之家  ›  专栏  ›  技术社区  ›  atlaste

删除原子/隔离数据中的数据

  •  0
  • atlaste  · 技术社区  · 9 年前

    假设我们在C++11程序中使用标准的消费者/生产者模式:(来自: http://en.cppreference.com/w/cpp/atomic/memory_order )

    #include <thread>
    #include <atomic>
    #include <cassert>
    #include <string>
    
    std::atomic<std::string*> ptr;
    int data;
    
    void producer()
    {
        std::string* p = new std::string("Hello");
        ptr.store(p, std::memory_order_release);
    }
    
    void consumer()
    {
        std::string* p2;
        while (!(p2 = ptr.load(std::memory_order_consume)))
            ;
        assert(*p2 == "Hello"); // never fires: *p2 carries dependency from ptr
    
        // yea well, it actually uses p2 for quite a while probably....
    }
    
    int main()
    {
        std::thread t1(producer);
        std::thread t2(consumer);
        t1.join(); t2.join();
    }
    

    现在,我想稍微改变一下生产者代码的行为。我不想简单地设置字符串,而是希望它 覆盖 字符串。例如。:

    void producer()
    {
        std::string* p = new std::string("Hello");
        ptr.store(p, std::memory_order_release);
    
        // do some stuff
    
        std::string* p2 = new std::string("Sorry, should have been Hello World");
        ptr.store(p2, std::memory_order_release);
    
        // **
    }
    

    这里的制作人负责弦的生成,这意味着在我的简单世界中,它也应该对这些弦的破坏负责。

    因此,在标有“**”的行中,我们应该销毁字符串“p”,这就是这个问题的意义所在。

    您可能会考虑的解决方案是添加(在标记行处):

    delete p;
    

    然而,这会破坏程序,因为在我们删除字符串之后,使用者可能会使用字符串——毕竟,使用者使用的是指针。此外,这意味着生产者等待消费者,这是不必要的——我们只是想清理我们的旧记忆。使用引用计数智能指针似乎是不可能的,因为原子只支持这么多类型。

    解决此问题的最佳(最有效)方法是什么?

    1 回复  |  直到 9 年前
        1
  •  2
  •   danielschemmel    9 年前

    你可以做一个 atomic exchange ,它将返回原子变量的上一个值。

    变量 ptr 然后有两种状态:要么没有可用数据,在这种情况下等于 nullptr ,或具有可供消费的数据。

    消费 任何消费者都可以交换的数据 指针 用一个 空指针 .

    • 如果没有数据,那么仍然没有任何数据,消费者将不得不稍后再试(这实际上构建了一个自旋锁)。

    • 如果有数据,消费者现在拥有所有权,并在不再需要时负责删除数据。

    生产 数据,生产者交换 指针 具有指向所产生的数据的指针。

    • 如果没有数据,上一个指针将等于 空指针 并且成功地产生了数据。
    • 如果有数据,生产者将有效地收回先前生产数据的所有权。然后,它可以删除该对象,或者更有效地将其重新用于下一个产品。