我有一个由两个线程同时使用的共享状态。在某些时候,两个线程都使用共享状态完成;它已经没有用了,必须删除。
问题:使用
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++ 标准是否允许这样的构造。
我的项目有一个这些状态的自定义链接列表,我的目标是防止列表增长失控。如果我给一个线程明确的状态所有权,它还将负责定期执行清理例程。我正在努力避免这种机制。
如果我可以在两个线程都完成后立即删除列表中的节点,那就太好了。
这绝对不安全。
您的标志包含在您要删除的对象内。因此,第二个线程可能会访问已删除的对象,这最多会导致访问冲突错误,最坏的情况会导致未定义行为(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