tars源码漫谈第28篇------tc_singleton.h(多线程下的单例)

2024-02-06 11:08

本文主要是介绍tars源码漫谈第28篇------tc_singleton.h(多线程下的单例),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

       要写一个单例, 很简单。 但是, 如果考虑多线程, 还真不是容易的事, 来看看tc_singleton.h:

/*** Tencent is pleased to support the open source community by making Tars available.** Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved.** Licensed under the BSD 3-Clause License (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at** https://opensource.org/licenses/BSD-3-Clause** Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License.*/#ifndef __TC_SINGLETON_H__
#define __TC_SINGLETON_H__#include "util/tc_monitor.h"
#include <cassert>
#include <cstdlib>namespace tars
{
/
/** * @file tc_singleton.h * @brief  单件类 .  *  * 单件实现类* * 没有实现对单件生命周期的管理,使用示例代码如下:* * class A : public TC_Singleton<A, CreateStatic,  DefaultLifetime>* * {* *  public:* *    A(){cout << "A" << endl;}* *   ~A()* *   {* *     cout << "~A" << endl;* * *    }**    void test(){cout << "test A" << endl;}* * };* 对象的创建方式由CreatePolicy指定, 有如下方式:* * CreateUsingNew: 在堆中采用new创建* * CreateStatic`: 在栈中采用static创建* * 对象生命周期管理由LifetimePolicy指定, 有如下方式:* * DefaultLifetime:缺省声明周期管理* *如果单件对象已经析够, 但是还有调用, 会触发异常 * * PhoneixLifetime:不死生命周期* * 如果单件对象已经析够, 但是还有调用, 会再创建一个* * NoDestroyLifetime:不析够* * 对象创建后不会调用析够函数析够, 通常采用实例中的方式就可以了**/              
//*** @brief 定义CreatePolicy:定义对象创建策略*/
template<typename T>
class CreateUsingNew
{
public:/*** @brief  创建.*  * @return T**/static T* create() { return new T; }/*** @brief 释放. *  * @param t*/static void destroy(T *t) { delete t; }
};template<typename T>
class CreateStatic
{
public:/*** @brief   最大的空间*/ union MaxAlign { char t_[sizeof(T)]; long double longDouble_; }; /*** @brief   创建. * * @return T**/static T* create() { static MaxAlign t; return new(&t) T; }/*** @brief   释放. *  * @param t*/static void destroy(T *t) {t->~T();}
};/*** @brief 定义LifetimePolicy:定义对象的声明周期管理*/
template<typename T>
class DefaultLifetime
{
public:static void deadReference(){throw std::logic_error("singleton object has dead.");}static void scheduleDestruction(T*, void (*pFun)()){std::atexit(pFun);}
};template<typename T>
class PhoneixLifetime
{
public:static void deadReference(){_bDestroyedOnce = true;}static void scheduleDestruction(T*, void (*pFun)()){if(!_bDestroyedOnce)std::atexit(pFun);}
private:static bool _bDestroyedOnce; 
};
template <class T> 
bool PhoneixLifetime<T>::_bDestroyedOnce = false; template <typename T> 
struct NoDestroyLifetime 
{ static void scheduleDestruction(T*, void (*)()) {} static void deadReference() {} 
}; //
// Singleton
template
<typename T,template<class> class CreatePolicy   = CreateUsingNew,template<class> class LifetimePolicy = DefaultLifetime
>
class TC_Singleton 
{
public:typedef T  instance_type;typedef volatile T volatile_type;/*** @brief 获取实例* * @return T**/static T *getInstance(){//加锁, 双check机制, 保证正确和效率if(!_pInstance){TC_ThreadLock::Lock lock(_tl);if(!_pInstance){if(_destroyed){LifetimePolicy<T>::deadReference();_destroyed = false;}_pInstance = CreatePolicy<T>::create();LifetimePolicy<T>::scheduleDestruction((T*)_pInstance, &destroySingleton);}}return (T*)_pInstance;}virtual ~TC_Singleton(){}; protected:static void destroySingleton(){assert(!_destroyed);CreatePolicy<T>::destroy((T*)_pInstance);_pInstance = NULL;_destroyed = true;}
protected:static TC_ThreadLock    _tl;static volatile T*      _pInstance;static bool             _destroyed;protected:TC_Singleton(){}TC_Singleton (const TC_Singleton &); TC_Singleton &operator=(const TC_Singleton &);
};template <class T, template<class> class CreatePolicy, template<class> class LifetimePolicy> 
TC_ThreadLock TC_Singleton<T, CreatePolicy, LifetimePolicy>::_tl; template <class T, template<class> class CreatePolicy, template<class> class LifetimePolicy> 
bool TC_Singleton<T, CreatePolicy, LifetimePolicy>::_destroyed = false; template <class T, template<class> class CreatePolicy, template<class> class LifetimePolicy> 
volatile T* TC_Singleton<T, CreatePolicy, LifetimePolicy>::_pInstance = NULL; }#endif

        写得够风骚。如果没太读懂, 也没什么关系, 后面主要是单例的使用。 

        如果有必要看多线程单例的具体细节, 再看。

 

 

 

这篇关于tars源码漫谈第28篇------tc_singleton.h(多线程下的单例)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/684117

相关文章

SpringBoot中使用 ThreadLocal 进行多线程上下文管理及注意事项小结

《SpringBoot中使用ThreadLocal进行多线程上下文管理及注意事项小结》本文详细介绍了ThreadLocal的原理、使用场景和示例代码,并在SpringBoot中使用ThreadLo... 目录前言技术积累1.什么是 ThreadLocal2. ThreadLocal 的原理2.1 线程隔离2

Java多线程父线程向子线程传值问题及解决

《Java多线程父线程向子线程传值问题及解决》文章总结了5种解决父子之间数据传递困扰的解决方案,包括ThreadLocal+TaskDecorator、UserUtils、CustomTaskDeco... 目录1 背景2 ThreadLocal+TaskDecorator3 RequestContextH

C#多线程编程中导致死锁的常见陷阱和避免方法

《C#多线程编程中导致死锁的常见陷阱和避免方法》在C#多线程编程中,死锁(Deadlock)是一种常见的、令人头疼的错误,死锁通常发生在多个线程试图获取多个资源的锁时,导致相互等待对方释放资源,最终形... 目录引言1. 什么是死锁?死锁的典型条件:2. 导致死锁的常见原因2.1 锁的顺序问题错误示例:不同

浅析Rust多线程中如何安全的使用变量

《浅析Rust多线程中如何安全的使用变量》这篇文章主要为大家详细介绍了Rust如何在线程的闭包中安全的使用变量,包括共享变量和修改变量,文中的示例代码讲解详细,有需要的小伙伴可以参考下... 目录1. 向线程传递变量2. 多线程共享变量引用3. 多线程中修改变量4. 总结在Rust语言中,一个既引人入胜又可

Go中sync.Once源码的深度讲解

《Go中sync.Once源码的深度讲解》sync.Once是Go语言标准库中的一个同步原语,用于确保某个操作只执行一次,本文将从源码出发为大家详细介绍一下sync.Once的具体使用,x希望对大家有... 目录概念简单示例源码解读总结概念sync.Once是Go语言标准库中的一个同步原语,用于确保某个操

Java汇编源码如何查看环境搭建

《Java汇编源码如何查看环境搭建》:本文主要介绍如何在IntelliJIDEA开发环境中搭建字节码和汇编环境,以便更好地进行代码调优和JVM学习,首先,介绍了如何配置IntelliJIDEA以方... 目录一、简介二、在IDEA开发环境中搭建汇编环境2.1 在IDEA中搭建字节码查看环境2.1.1 搭建步

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

在JS中的设计模式的单例模式、策略模式、代理模式、原型模式浅讲

1. 单例模式(Singleton Pattern) 确保一个类只有一个实例,并提供一个全局访问点。 示例代码: class Singleton {constructor() {if (Singleton.instance) {return Singleton.instance;}Singleton.instance = this;this.data = [];}addData(value)

Java ArrayList扩容机制 (源码解读)

结论:初始长度为10,若所需长度小于1.5倍原长度,则按照1.5倍扩容。若不够用则按照所需长度扩容。 一. 明确类内部重要变量含义         1:数组默认长度         2:这是一个共享的空数组实例,用于明确创建长度为0时的ArrayList ,比如通过 new ArrayList<>(0),ArrayList 内部的数组 elementData 会指向这个 EMPTY_EL

如何在Visual Studio中调试.NET源码

今天偶然在看别人代码时,发现在他的代码里使用了Any判断List<T>是否为空。 我一般的做法是先判断是否为null,再判断Count。 看了一下Count的源码如下: 1 [__DynamicallyInvokable]2 public int Count3 {4 [__DynamicallyInvokable]5 get