Singleton Synchronization C++
如果我必须在C ++中编写单例类,我将使用静态变量,私有构造函数& 一个返回类对象的公共静态函数。 但是在多线程环境中,代码会出现问题。 为了避免多个线程同时访问同一个变量,Boost线程是用于同步的最佳机制吗? 我的意思是在资源上设置/取消设置锁/互斥锁。 在C ++标准库中是否有其他内置的内容,我不必下载boost,构建东西等? 我听说过C ++ Ox但不太了解。
C ++ 98/03完全不支持线程。如果您正在使用C ++ 98或03编译器,那么您几乎不得不使用Boost,或某些(或多或少)特定于操作系统的东西,例如pthreads或Win32的线程原语。
C ++ 11有一个相当完整的线程支持库,包括互斥锁,锁,线程本地存储等。
然而,我觉得有必要指出,备份并做更多考虑是否需要/想要一个Singleton可能会更好。说实话,单身模式在很大程度上已经失宠了。
编辑:重读这个,我有点想跳过一件事:至少当我使用它们时,任何/所有单例都在任何辅助线程启动之前完全初始化。这引起了对初始化中线程安全性的关注,这完全没有实际意义。我想在你启动辅助线程之前你可能有一个你无法初始化的单例,所以你需要处理这个问题,但至少对它来说这是一个非常不寻常的例外,我只会在/如果绝对必要。
对我来说,使用c ++ 11实现单例的最佳方法是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | class Singleton { public: static Singleton & Instance() { // Since it's a static variable, if the class has already been created, // It won't be created again. // And it **is** thread-safe in C++11. static Singleton myInstance; // Return a reference to our instance. return myInstance; } // delete copy and move constructors and assign operators Singleton(Singleton const&) = delete; // Copy construct Singleton(Singleton&&) = delete; // Move construct Singleton& operator=(Singleton const&) = delete; // Copy assign Singleton& operator=(Singleton &&) = delete; // Move assign // Any other public methods protected: Singleton() { // Constructor code goes here. } ~Singleton() { // Destructor code goes here. } // And any other protected methods. } |
这是一个c ++ 11功能,但通过这种方式,您可以创建一个线程安全的Singleton。根据新标准,不再需要关心这个问题。对象初始化只能由一个线程完成,其他线程将等待它完成。或者你可以使用std :: call_once。
如果要对单例资源进行独占访问,则必须对这些函数使用锁定。
不同类型的锁:
使用atomic_flg_lck:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | class SLock { public: void lock() { while (lck.test_and_set(std::memory_order_acquire)); } void unlock() { lck.clear(std::memory_order_release); } SLock(){ //lck = ATOMIC_FLAG_INIT; lck.clear(); } private: std::atomic_flag lck;// = ATOMIC_FLAG_INIT; }; |
使用原子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | class SLock { public: void lock() { while (lck.exchange(true)); } void unlock() { lck = true; } SLock(){ //lck = ATOMIC_FLAG_INIT; lck = false; } private: std::atomic<bool> lck; }; |
使用互斥锁:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | class SLock { public: void lock() { lck.lock(); } void unlock() { lck.unlock(); } private: std::mutex lck; }; |
仅适用于Windows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | class SLock { public: void lock() { EnterCriticalSection(&g_crit_sec); } void unlock() { LeaveCriticalSection(&g_crit_sec); } SLock(){ InitializeCriticalSectionAndSpinCount(&g_crit_sec, 0x80000400); } private: CRITICAL_SECTION g_crit_sec; }; |
原子和atomic_flg_lck使线程保持旋转计数。 Mutex只是睡觉了。如果等待时间太长也许最好睡眠线程。最后一个"CRITICAL_SECTION"使线程保持旋转计数直到消耗时间,然后线程进入休眠状态。
如何使用这些关键部分?
1 2 3 4 5 6 7 | unique_ptr<SLock> raiilock(new SLock()); class Smartlock{ public: Smartlock(){ raiilock->lock(); } ~Smartlock(){ raiilock->unlock(); } }; |
使用raii成语。用于锁定关键部分的构造函数和用于解锁它的析构函数。
例
1 2 3 4 5 6 7 8 | class Singleton { void syncronithedFunction(){ Smartlock lock; //..... } } |
此实现是线程安全且异常安全的,因为变量锁保存在堆栈中,因此当函数作用域结束(函数结束或异常)时,将调用析构函数。
我希望你觉得这很有帮助。
谢谢!!