使用原子引用计数时是否需要保护delete资源?

时间:2014-09-26 00:51:29

标签: c++ multithreading reference-counting

在许多情况下,资源可以由多个线程共享。资源处理程序可以使用原子引用计数来处理这些资源。

假设您在线程A中有一个资源处理程序,例如std::string a。假设此std::string在内部使用原子引用计数机制。现在假设您制作了一个卷影副本,例如std::string b=a,其中b用于主题B.

我刚读过这个问题:reference counted class and multithreading,那里有两个答案。 first answer表示下面的代码段足够了;注意cleanup没有任何互斥保护:

if(InterlockedDecrement(&mRefCount)==0)
    cleanup();

second answer使用互斥锁包装cleanup函数:

void decRef() {
    lock(_mutex);
    if(InterlockedDecrement(&mRefCount)==0) {
        cleanup(); //mainly delete some resource
    }
}

我的问题是,“第一个答案是否正确?”当在线程A中销毁实例a时,这种情况怎么样:

if(InterlockedDecrement(&mRefCount)==0)
    // here, OS switch to another thread, and mRefCount is changed there
    cleanup();

...其中mRefCount可以在线程B中同时更改(b。)在线程B发生这样的更改之后,在线程中调用cleanup()是否仍然安全?A

1 个答案:

答案 0 :(得分:3)

我还没有尝试过很详细地回答这个问题,但我怀疑你一般关心的问题不仅仅是那个问题。

在典型的COW字符串 1 中,当引用计数降至0时,您不再需要使用互斥锁(或类似的东西)来保护清理。

原因很简单:至少在通常情况下,您只能通过复制对字符串的一些现有引用来创建对字符串的新引用。当引用计数降为零时, 不再是任何现有引用,因此没有来源可以创建这样的副本。

如果您使用其他而不是COW字符串,则必须查看用法以确定引用计数是否可能从起始值增加例如,您可以使用某种缓存来保存最近使用的值,这些值使用引用计数,因此只要引用了对象,它就会保留在缓存中。如果不存在对它的进一步引用,则从高速缓存中删除它将符合条件。下次需要向缓存添加内容时,您将找到引用计数为0的最旧项目,并将其替换为新项目(如果没有项目的引用计数为0,则您和#39; d根据缓存策略扩展缓存或拒绝缓存新项目。

在这种情况下, 可以找到引用计数为0的任何项目,然后有一个上下文切换,添加对该项目的引用,然后切换回来(如果你没有使用互斥锁保护清理)删除项目,即使它现在具有非零引用计数。


1.虽然它在这里并不特别重要,但标准现在明确禁止std::string的写时复制实现。 功能