chrome-RefCountedThreadSafe所谓的线程安全是什么?

RefCountedThreadSafe的引用计数是原子操作的,所以网上查到的统一的说法线程安全,RefCountedThreadSafe也有很多非原子操作,它所谓的线程安全是什么意思
比如用scoped_refptr操作RefCountedThreadSafe跨线程会线程安全吗?

写个简单的示例测试:

class Test : public base::RefCountedThreadSafe<Test>
{
public:
    Test(){}

private:
     friend class base::RefCountedThreadSafe<Test>;
    ~Test()
    {
        int i = 0;
    }
};
scoped_refptr<Test> g_pTest;
DWORD WINAPI ThreadProc1(LPVOID lpParameter)
{
    g_pTest = NULL;
    return 0;
}

DWORD WINAPI ThreadProc2(LPVOID lpParameter)
{
    scoped_refptr<Test> pOther;
    if (g_pTest)
    {
        pOther = g_pTest;
    }
    return 0;
}

void Fun()
{
    g_pTest = new Test;
    DWORD dwThreadId1 = 0;
    ::CreateThread(NULL,0,ThreadProc1,NULL,0,&dwThreadId1);

    DWORD dwThreadId2 = 0;
    ::CreateThread(NULL,0,ThreadProc2,NULL,0,&dwThreadId2);
}

上面是两个线程,一个测试函数,先在ThreadProc1和ThreadProc2中分别设置断点,一般会先断在ThreadProc1中, 初始g_pTest的引用计数为1,见下图:
这里写图片描述

单步调试跳转进去,在scoped_refptr<T>& operator=(T* p)
设置个断点,如下图:
这里写图片描述

此时,切换到ThreadProc2线程:
因为g_pTest还没执行ptr_赋值,所以ptr_是有值的,即if (g_pTest)是OK的,因为有pOther = g_pTest;,scoped_refptr同样会走到赋值操作scoped_refptr<T>& operator=(T* p)中,注意,这是在ThreadProc2线程中,我们在它执行AddRef(即引用计数还没有+1)之前断下:
这里写图片描述

此时,切换回ThreadProc1线程:
让ThreadProc1执行完它的赋值再delete操作,最终走到Test的析构函数,即0x01c85588这个地址被释放了
这里写图片描述

此时,切换到ThreadProc2线程:
它要执行p->AddRef,因为p(0x01c85588),这个地址已经被释放,那么这个 ptr_->倒底会出现什么样的错误,就不得而知了,
这里写图片描述
最后在pOther释放时, 弹出如下框:
这里写图片描述
这里写图片描述

所以scoped_refptr这么使用RefCountedThreadSafe应该不是线程安全的,同样测试WeakPtr,在is_valid_ = false之前,让WeakPtr先get,是有效的,但实际对象已被析构,也会OVER,
但是如果我们在调用线程 先AddRef,在其他线程去Release,感觉还是线程安全的,比如典型的Task

为什么要避免引用计数?

Chromium智能指针指引中的解释:

Reference-counted objects make it difficult to understand ownership and destruction order, especially when multiple threads are involved. There is almost always another way to design your object hierarchy to avoid refcounting. Avoiding refcounting in multithreaded situations is usually easier if you restrict each class to operating on just one thread, and use PostTask() and the like to proxy calls to the correct thread. base::Bind(), WeakPtr, and other tools make it possible to automatically cancel calls to such an object when it dies. Note that too much of our existing code uses refcounting, so just because you see existing code doing it does not mean it’s the right solution. (Bonus points if you’re able to clean up such cases.)

猜你喜欢

转载自blog.csdn.net/hgy413/article/details/78884914