【问题标题】:Threadsafe delete in C++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 上的删除操作会影响我的新对象。

【问题讨论】:

  • 为什么需要这个?对线程之间共享的对象的任何变异操作都需要锁定。为什么要单独删除?无论如何,我认为您描述的情况没有问题。新的对象地址可能与旧的已删除对象地址相同,这有什么影响?
  • 但是我有一个事件系统,它可能在不同的侦听器中拥有相同的指针(甚至是相同的侦听器,因为它们可以在不同的线程中执行)。
  • 我不知道你为什么认为这很重要。当一个对象还活着时,只有那个对象有这个地址。当一个对象被删除时,该地址的对象就不再存在,它可以被重用。如果您在程序周围保留可能已删除对象的地址,那么您就会遇到与线程无关的问题。

标签: c++ multithreading c++11 delete-operator


【解决方案1】:

通常你不应该假设用于旧对象的指针不会被新对象重用。

有时你会想做出这样的假设。

对于多线程程序,当你想确保指针不被重复使用时,这种情况是 ABA 问题。简单来说,这个问题发生在旧指针和新指针比较交换时,但不能确定旧指针确实是旧指针。

一种解决方案基本上是将旧指针保留一段时间,这称为Hazard pointer

另一种是不仅仅依赖指针值,还依赖一个计数器(虽然计数器仍然可以回绕,但是失败的概率更低)。

一般来说,最好的解决方案是不要遇到需要假设旧指针未被重用的情况。 ABA 问题 是特殊情况,但是,特定于无锁,当避免可能意味着根本没有无锁算法时。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-07
    • 1970-01-01
    • 1970-01-01
    • 2015-02-16
    • 2015-10-26
    • 1970-01-01
    相关资源
    最近更新 更多