C++中的线程安全删除
Posted
技术标签:
【中文标题】C++中的线程安全删除【英文标题】:Threadsafe delete in C++ 【发布时间】:2020-07-12 08:21:32 【问题描述】:我的问题不是如何从头开始制作这个功能,而是我的实现是否可以使用。
我有下一堂课:
class PointerStorage
private:
static std::mutex m;
static std::unordered_set<void*> pointers;
public:
static inline void add(void* ptr)
m.lock();
PointerStorage::pointers.insert(ptr);
m.unlock();
static inline bool tryRemove(void* ptr)
std::lock_guard<std::mutex> g(m);
return PointerStorage::pointers.erase(ptr);
static inline bool hasPtr(void* ptr)
std::lock_guard<std::mutex> g(m);
return PointerStorage::pointers.find(ptr) != PointerStorage::pointers.end();
;
class Deletable
public:
void* operator new(size_t size)
void* p = malloc(size);
PointerStorage::add(p);
return p;
void operator delete(void* ptr)
if (PointerStorage::tryRemove(ptr))
free(ptr);
;
我的想法是在必要时从Deletable
继承并使用运算符
但我想知道这种情况是否可能:
我在变量OBJ
中创建了一个对象,删除它。
我在另一个变量中创建了一个新对象,它的地址与OBJ
中的地址相同,OBJ
上的删除操作会影响我的新对象。
【问题讨论】:
为什么需要这个?对线程之间共享的对象的任何变异操作都需要锁定。为什么要单独删除?无论如何,我认为您描述的情况没有问题。新的对象地址可能与旧的已删除对象地址相同,这有什么影响? 但是我有一个事件系统,它可能在不同的侦听器中拥有相同的指针(甚至是相同的侦听器,因为它们可以在不同的线程中执行)。 我不知道你为什么认为这很重要。当一个对象还活着时,只有那个对象有这个地址。当一个对象被删除时,该地址的对象就不再存在,它可以被重用。如果您在程序周围保留可能已删除对象的地址,那么您就会遇到与线程无关的问题。 【参考方案1】:通常你不应该假设用于旧对象的指针不会被新对象重用。
有时你会想做出这样的假设。
对于多线程程序,当你想确保指针不被重复使用时,这种情况是 ABA 问题。简单来说,这个问题发生在旧指针和新指针比较交换时,但不能确定旧指针确实是旧指针。
一种解决方案基本上是将旧指针保留一段时间,这称为Hazard pointer。
另一种是不仅仅依赖指针值,还依赖一个计数器(虽然计数器仍然可以回绕,但是失败的概率更低)。
一般来说,最好的解决方案是不要遇到需要假设旧指针未被重用的情况。 ABA 问题 是特殊情况,但是,特定于无锁,当避免可能意味着根本没有无锁算法时。
【讨论】:
以上是关于C++中的线程安全删除的主要内容,如果未能解决你的问题,请参考以下文章