Browse Source

提交部分单例模式的实现

Gogs 2 months ago
parent
commit
8a545c948e
3 changed files with 97 additions and 1 deletions
  1. 1 1
      .gitignore
  2. 95 0
      signal.cpp
  3. 1 0
      test/buid.sh

+ 1 - 1
.gitignore

@@ -1,7 +1,7 @@
 test/builder
 test/CRTP
 test/factory
-
+test/signal
 
 
 .vscode/

+ 95 - 0
signal.cpp

@@ -0,0 +1,95 @@
+//单例模式,也带点过度设计的无聊美感
+//单例模式是一种强制性的约束,一个物体全局只有唯一实例
+//在C/cpp中完全可以用全局变量实现(C++允许在函数外构建对象实例)
+//当然java就比较麻烦了,java不允许出现全局变量,单例模式似乎是唯一选择
+
+
+//单例模式的核心是C系语言静态变量的特性
+//所有的静态变量的生命周期都是全局的
+//C系语言中有三种静态变量,分别是类作用域,局部作用域和全局作用域
+//类作用域的静态变量所有的实例中只有唯一的副本,并且在访问的时候访问的是唯一的静态变量
+//局部作用域的静态变量,作用域只有局部,但是生命周期是全局(由于不进行链接,因此不会创建额外的副本)
+//全局静态变量的作用域是全局,但是只有内部链接性,即每一个包含头文件的的cpp文件中有一个独立的副本
+#include<atomic>
+#include<mutex>
+#include<thread>
+#include<iostream>
+//这个单例模式是内存安全的,在于cpp11之后现代cpp的static变量的构建是内存安全的
+class signal
+{
+protected:
+    signal()=default;
+    signal(const signal&)=delete;
+    signal(signal&&)=delete;
+    signal& operator=(const signal&)=delete;
+    signal& operator=(signal&&)=delete;
+public:
+    static signal& get()               //核心是引用返回的是内部构建的局部变量而不是一个copy后的副本
+    {
+        static signal data;
+        return data;
+    }
+};
+
+
+//懒汉式,以及cpp11之前的单例模式
+//使用双检锁保证初始化顺序
+class thread_signal
+{
+private:
+    //C++11之前没有这些类就需要使用boost实现
+    static std::atomic<thread_signal*> instance;
+    static std::mutex mtx;
+public:
+    static thread_signal* get()
+    {
+        thread_signal* data=instance.load(std::memory_order_acquire);
+        if(data==nullptr)
+        {
+            std::lock_guard<std::mutex> lock(mtx);
+            data=instance.load(std::memory_order_relaxed);        //重新加载一次防止在前面的判断过程中已经被改变,由于在锁的范围,直接用宽松内存序就好
+            if(data==nullptr)
+            {
+                data=new thread_signal();
+                instance.store(data,std::memory_order_relaxed);
+            }
+        }
+        return data;            //由于初始化是唯一的因此只会初始化一次,不会出现改变   
+    }
+};
+
+
+//每线程单例
+class signal_thread_local
+{
+protected:
+    signal_thread_local(int _i):i(_i){};
+    signal_thread_local(const signal_thread_local&)=delete;
+    signal_thread_local(signal_thread_local&&)=delete;
+    signal_thread_local& operator=(const signal_thread_local&)=delete;
+    signal_thread_local& operator=(signal_thread_local&&)=delete;
+public:
+    int i;
+    static signal_thread_local& get()               //核心是引用返回的是内部构建的局部变量而不是一个copy后的副本
+    {
+        thread_local signal_thread_local data(0);            //构建线程作用域的单例
+        return data;
+    }
+};
+
+
+void fun(int j)
+{
+    signal_thread_local& re1=signal_thread_local::get();
+    re1.i=re1.i+j;
+    signal_thread_local& re2=signal_thread_local::get();
+    std::cout<<re2.i<<std::endl;
+}
+
+int main()
+{
+    auto i1=std::thread(fun,1);
+    auto i2=std::thread(fun,2);
+    i1.join();
+    i2.join();
+}

+ 1 - 0
test/buid.sh

@@ -3,6 +3,7 @@ echo "开始构建"
 g++ -O3 ../CRTP.cpp -o CRTP -std=c++20
 g++ -O3 ../builder.cpp -o builder -std=c++20
 g++ -O3 ../factory.cpp  -o factory -std=c++20
+
 echo "开始运行"
 ./builder
 ./CRTP