Linux系统C++中多线程Singleton的实现

原文链接:http://blog.chinaunix.net/uid-29686891-id-4284971.html

我想关于Singleton模式的实现和资料很多很多,这里为什么专门拿出来写一写,还是因为个人觉得要想把单例模式写好还真不是一件容易的事情。
其中涉及到不少编译和底层的知识。这里以Linux平台为例,这是因为本人对windows下的编程实在不太熟悉。

本文所有代码均上传至github仓库:https://github.com/kevin-shanghai/Programming_Practice
如果有兴趣,可以随意获取,本代码仅用于测试,如用于生产环境发生任何问题,本人概不负责。

本文针对于线程安全的Singleton实现,并基于模板,这样通用性更好,否则对于每个类都要实现自己的单例模式。
一般的单线程下的Singleton实现非常简单,用一个静态成员函数返回该类的一个实例就行了,但是遇到多线程,事情就麻烦了不少。
废话少说,下面看下具体代码:

/**********************************************

2.  ******* g++ test.cpp -lpthread****************

3.  * *******************************************/

4. #include <iostream>

5. #include <pthread.h>

6. using namespace std;

7. template <class T>

8.class Singleton

9.{

10.public:

11.     Singleton()

12.     {

13.

14.     }

15.     static T* GetInstance()

16.     {

17.        if(m_pInstance == NULL)

18.         {

19.             pthread_mutex_lock(&mutex);

20.             if(m_pInstance == NULL)

21.             {

22.                 T* temp = new T;

23.                 m_pInstance = temp;

24.             }

25.             pthread_mutex_unlock(&mutex);

26.         }

27.         return m_pInstance;

28.     }

29.private:

30.     static T* m_pInstance;

31.     static pthread_mutex_t mutex;

32.};

33.

34. template<class T>

35. T* Singleton<T>::m_pInstance = NULL;

36.

37. template<class T>

38. pthread_mutex_t Singleton<T>::mutex;

39.

40.class Test:public Singleton<Test>

41.{

42.public:

43.     Test()

44.     {

45.         cout<<"Test::Test()."<<endl;

46.     }

47.};

48.

49. void* thread1(void*)

50.{

51.     cout<<"In thread1."<<endl;

52.     Test* test1 = Test::GetInstance();

53.}

54.

55. void* thread2(void *)

56.{

57.     cout<<"In thread2."<<endl;

58.     Test* test2 = Test::GetInstance();

59.}

60.

61.int main()

62.{

63.     const unsigned int thread_num = 20;

64.     pthread_t thread_id[thread_num];

65.     for(unsigned int i = 0; i<thread_num;i++)

66.     {

67.         pthread_create(&thread_id[i], NULL, thread1, NULL);

68.     }

69.     for(unsigned int i = 0; i<thread_num;i++)

70.     {

71.         pthread_create(&thread_id[i], NULL, thread2, NULL);

72.     }

73.     sleep(1);

74.     return 0;

75.} 

可以看到上面的代码中使用了double-check机制,也就是对m_pInstance检查了两遍,这样有利于提高性能。还有一点需要注意的是
T* temp = new T; m_pInstance = temp;而没有直接用m_pInstance = new T;这是因为这一语句将会分为三步来执行:
1. 非配内存
2. 用相应的实例初始化该内存区域
3. 将该内存地址赋值给该指针m_pInstance
如果其中第2步骤和第3步或者第一步骤颠倒了,也就是编译器对我们的代码进行了优化,那么赋值给m_pInsannce指针的就是没有初始化的
所以我们用一个临时变量解决这个问题

其实Linux平台下的singleton模式有更简单的实现方式,主要是利用pthread_once这个api,看代码:

#include <iostream>

2. #include <pthread.h>

3. using namespace std;

4. template<class T>

5.class Singleton

6.{

7.public:

8.     static T& instance()

9.     {

10.         pthread_once(&m_Once, &Singleton::init);

11.         return *m_tValue;

12.     }

13.

14.private:

15.     Singleton();

16.     ~Singleton();

17.     static void init()

18.     {

19.         m_tValue = new T();

20.     }

21.

22.private:

23.     static pthread_once_t m_Once;

24.     static T* m_tValue;

25.};

26.

27. template<class T>

28. pthread_once_t Singleton<T>::m_Once = PTHREAD_ONCE_INIT;

29.

30. template<class T>

31. T* Singleton<T>::m_tValue = NULL;

32.

33.

34.class Test

35.{

36.public:

37.     Test()

38.     {

39.         cout<<"In Test::Test()."<<endl;

40.     }

41.};

42.

43. void* thread_func(void*)

44.{

45.     Test& t = Singleton<Test>::instance();

46.}

47.

48.int main(int argc, char const *argv[])

49.{

50.//    Test& t = Singleton<Test>::instance();

51.     pthread_t thread_id[10];

52.     for(int i=0;i<10;i++)

53.     {

54.         pthread_create(&thread_id[i], NULL, thread_func, NULL);

55.     }

56.     return 0;

57.} 


其实这种方式在Linux平台下比较简单,pthread_once保证Init函数只执行一次,建议Linux下大家用这种方法来实现。
这种单件模式比较通用,而且在多线程环境下也很稳定,如果大家要实现跨平台的singleton模式,那么可以加上相应平台的
创建线程的api就可以了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值