使用 std::atomic_flag 作为同步机制删除共享状态是否安全

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

我有一个由两个线程同时使用的共享状态。在某些时候,两个线程都使用共享状态完成;它已经没有用了,必须删除。

问题:使用

std::atomic_flag
作为同步机制来确定哪个线程应该删除共享状态是否安全/可接受/允许?

#include <atomic>
#include <thread>

struct State
{
    std::atomic_flag flag;

    auto eliminate() {
        // Setting the flag signals that a thread is done with the state;
        // the second thread should then also delete the state.
        if (flag.test_and_set())
            delete this;
    }
};

int main()
{
    auto s = new State{};
    auto t1 = std::thread{[=] { s->eliminate(); }};
    auto t2 = std::thread{[=] { s->eliminate(); }};
    t1.join();
    t2.join();
}

我知道一旦调用

eliminate
返回,任何一个线程都必须将共享状态视为已删除。

我认为实现是安全的,因为在调用

test_and_set
后不再访问状态成员,但我不确定 C++ 标准是否允许这样的构造。

我的项目有一个这些状态的自定义链接列表,我的目标是防止列表增长失控。如果我给一个线程明确的状态所有权,它还将负责定期执行清理例程。我正在努力避免这种机制。

如果我可以在两个线程都完成后立即删除列表中的节点,那就太好了。

c++ multithreading c++20 atomic
1个回答
0
投票

这绝对不安全。

您的标志包含在您要删除的对象内。因此,第二个线程可能会访问已删除的对象,这最多会导致访问冲突错误,最坏的情况会导致未定义行为(UB),可能会再次删除该对象(如果删除将内存归零,则可能是某种调试编译模式)或使用自定义全局分配器)。

想象一下这个模式:

thread1: if (flag.test_and_set())
thread1:     delete this;
// Now any access to this->flag, from this thread or any other thread will be UB because of the delete
thread2: if (flag.test_andset()) // UB
© www.soinside.com 2019 - 2024. All rights reserved.