简体   繁体   English

是否可以自动对 singleton object 线程安全进行原子操作

[英]Is it possible to make atomic operations on singleton object thread safe automatically

I have singleton object shared between two units operating on seperate threads.我有 singleton object 在两个在单独线程上运行的单元之间共享。 For example,例如,

Thread A Singleton.getInstace().incCounter();线程 A Singleton.getInstace().incCounter();

Thread B Singleton.getInstance().decCounter();线程 B Singleton.getInstance().decCounter();

Is it possible to implement this atomics to be thread safe without bothering the consumers to do it in thread safe way.是否可以将这个原子实现为线程安全的,而不用打扰消费者以线程安全的方式进行操作。

Something like就像是

static Singleton& GetInstance() {

    std::scoped_lock lock(m_mtx);

    static Singleton* singleton = new Singleton();

    return *singleton;
}

I guess this will not work as the lock will be released after the return but incCounter and decCounter will be called without the lock.我想这不会起作用,因为锁将在返回后被释放,但 incCounter 和 decCounter 将在没有锁的情况下被调用。 Is it somehow possible to keep the lock active till atomic operation is completed.是否有可能在原子操作完成之前保持锁处于活动状态。 Is doing a lock within the incCounter and decCounter the only solution here or in unit A and unit B only solution.在 incCounter 和 decCounter 内进行锁定是这里唯一的解决方案或在单元 A 和单元 B 中的唯一解决方案。

The current lock accomplishes nothing.当前的锁什么也没做。 A static function-local variable is required by the C++ standard to be initialized in exactly one thread. C++ 标准要求在一个线程中初始化static函数局部变量。 That is, the compiler will ensure that there can be no race conditions on its initialization.也就是说,编译器将确保在其初始化时不会出现竞争条件。 So the lock is protecting against something that can't happen.所以锁可以防止一些不可能发生的事情。

You need to put a lock in the increment/decrement functions.您需要在递增/递减函数中加锁。 And they need to lock the same mutex.他们需要锁定同一个互斥锁。 Though perhaps they could increment/decrement an atomic variable, in which case you don't need a lock at all.虽然也许他们可以增加/减少一个原子变量,在这种情况下你根本不需要锁。

You could (but probably shouldn't) create a new type LockedSingleton which stores a reference to the singleton and a std::unique_lock .可以(但可能不应该)创建一个新类型LockedSingleton ,它存储对 singletonstd::unique_lock的引用。 This would be what your GetInstance() returns.这将是您的GetInstance()返回的内容。 LockedSingleton would need to have its own increment/decrement functions which it forwards to its internal singleton reference, as well as any other interface functions. LockedSingleton需要有自己的递增/递减函数,它转发到其内部 singleton 参考,以及任何其他接口函数。

class LockedSingleton
{
private:
  std::unique_lock<std::mutex> lock_;
  Singleton &obj_;

private: //Only friends can construct. Also, non-copyable.
  LockedSingleton(std::mutex &mtx, Singleton &obj)
    : lock_(mtx)
    , obj_(obj)
  {}

  friend Singleton& GetInstance();

public:

  void incCounter() {obj.incCounter();}
  void decCounter() {obj.decCounter();}
    
};

static LockedSingleton GetInstance() {
    static Singleton* singleton = new Singleton();

    return LockedSingleton(m_mtx, *singleton);
}

Note that this only works in C++17 and above, due to guaranteed elision, since LockedSingleton is non-copyable.请注意,这仅适用于 C++17 及更高版本,由于保证省略,因为LockedSingleton是不可复制的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM