为什么原子操作还需要锁?

问题描述 投票:0回答:1

示例代码如下:

class ResourcePool{
public:   
    ...
    static inline ResourcePool* singleton()
    {
        ResourcePool* p = _singleton.load(butil::memory_order_consume);
        if (p) {
            return p;
        }
        pthread_mutex_lock(&_singleton_mutex);
        p = _singleton.load(butil::memory_order_consume);
        if (!p) {
            p = new ResourcePool();
            _singleton.store(p, butil::memory_order_release);
        }
        pthread_mutex_unlock(&_singleton_mutex);
        return p;
    }
private:
    ....
    static butil::static_atomic<ResourcePool*> _singleton;
    static pthread_mutex_t _singleton_mutex;
};

Butil:: memoryreorder_consume
是memoryreorder_consume的封装的boost内存顺序

第一个问题

在多核多线程环境下,第一个“butil::memoryreorder_consume”保证了指令的顺序,并防止其他线程在获取p指针之前解引用p?

第二个问题:

如果ResourcePool已经存在,则返回

 p=_singleton. load (but il:: memoryreorder_consume) between them
如果后面没有创建,则创建。后续的
 _singleton. store (p, but il:: memoryreorder-release)
应该已经通知给其他线程了,只要其他线程
 _singleton. load (p, but il:: memoryreorder-acquire)
这不是无锁实现,为什么要加锁?

如果需要加锁才能保证

 p=_singleton. load (butil:: memoryreorder_consume)
唯一访问,那么后面的
 _singleton. store (p, but il:: memoryreorder-release)
有什么用呢?

linux performance concurrency
1个回答
0
投票

您得到的是一个双重检查锁定的示例,众所周知,正确执行该操作非常困难。双重检查锁定的目标是确保在分配

_singleton_mutex
成员后,没有线程必须锁定
_singleton

互斥量的目的是防止多个线程构造

new ResourcePool()
。这是一个复杂的操作,除了使用互斥体之外,没有其他方法可以将构造函数调用和
_singleton
赋值转换为单个原子操作。

如果您不介意制作 singleton 函数的 乐观版本,那么您将

不需要
需要互斥体。乐观的版本可能允许多个线程构造一个新的
ResourcePool
,但它将保证所有调用者都会同意哪一个是真实的,并且它将保证所有额外的
ResourcePool
对象将被删除而不使用。

原子变量的目的当然是提供一种无锁的方式,以确保一旦

_singleton
被赋值,任何线程都不会误认为它没有被赋值。

© www.soinside.com 2019 - 2024. All rights reserved.