千家信息网

C++如何解决单例懒汉式和多线程问题

发表于:2025-02-20 作者:千家信息网编辑
千家信息网最后更新 2025年02月20日,这篇文章主要为大家展示了"C++如何解决单例懒汉式和多线程问题",内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下"C++如何解决单例懒汉式和多线程问题"这篇文章
千家信息网最后更新 2025年02月20日C++如何解决单例懒汉式和多线程问题

这篇文章主要为大家展示了"C++如何解决单例懒汉式和多线程问题",内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下"C++如何解决单例懒汉式和多线程问题"这篇文章吧。

单例懒汉式和多线程问题


作为单例模式,是在整个程序运行期间只会建立一份内存空间,为了达到这个目标
1、需要将构造函数设置为私有成员
2、需要一个私有的静态指针指向自身
3、需要一个公有的静态函数将这个上面的静态指针露出来

如下的代码就是一个懒汉式的单例

点击(此处)折叠或打开

  1. #include

  2. using namespace std;


  3. class single_ins

  4. {

  5. private:

  6. int a;

  7. int b;

  8. single_ins()

  9. {

  10. a= 0;

  11. b= 0;

  12. }

  13. static single_ins* myc;

  14. public:

  15. void setval(const int& a,const int& b)

  16. {

  17. this->a = a;

  18. this->b = b;

  19. }


  20. void print()

  21. {

  22. cout<<"a:"<

  23. cout<<"b:"<

  24. }



  25. static single_ins* setp()

  26. {

  27. //?

  28. if(myc == NULL)

  29. {

  30. myc = new single_ins;

  31. }

  32. //?

  33. return myc;

  34. }


  35. static void pfree()

  36. {

  37. if(myc != NULL)

  38. {

  39. delete myc;

  40. myc = NULL;

  41. }

  42. }


  43. };


  44. //? init static value

  45. single_ins* single_ins::myc = NULL;

  46. //nit static value

  47. //single_ins* single_ins::myc = new single_ins;


  48. int main()

  49. {

  50. single_ins* a = single_ins::setp();

  51. single_ins* b = single_ins::setp();

  52. a->setval(10,20);

  53. b->print();


  54. cout<

  55. single_ins::pfree();


  56. }

但是上面的代码有明显的问题,就是遇到多线程的情况下,因为多个线程如果同事创建内存,由于彼此之间
并不能及时检查到内存已经分配,会分配多个内存,这个时候我们至少需要一个线程间同步手段来让他们之间
串行的执行,这个时候就涉及到两次检查(double check)
如果没有mutex保护就是下面这个程序:

点击(此处)折叠或打开

  1. #include

  2. #include

  3. using namespace std;



  4. //单列模式

  5. class single_ins

  6. {

  7. private:

  8. int a;

  9. int b;

  10. single_ins()

  11. {

  12. cout<<"con begin\n";

  13. a= 0;

  14. b= 0;

  15. sleep(10); //故意拖长构造函数执行时间,造成懒汉式多线程问题

  16. cout<<"con end\n";

  17. }

  18. static single_ins* myc;//单例需要一个静态指针

  19. static int cnt;//构造调用次数统计

  20. public:

  21. void setval(const int& a,const int& b)

  22. {

  23. this->a = a;

  24. this->b = b;

  25. }


  26. void print()

  27. {

  28. cout<<"a:"<

  29. cout<<"b:"<

  30. cout<

  31. }



  32. static single_ins* setp() //函数获得指针值赋给静态成员指针变量

  33. {

  34. //懒汉式

  35. if(myc == NULL)

  36. {

  37. myc = new single_ins;

  38. cnt++;

  39. }

  40. //懒汉式

  41. return myc;

  42. }

  43. static void pfree()

  44. {

  45. if(myc != NULL)

  46. {

  47. delete myc;

  48. myc = NULL;

  49. }

  50. }

  51. };


  52. //懒汉式 init static value

  53. single_ins* single_ins::myc = NULL;

  54. int single_ins::cnt = 0;

  55. //饿汉试 init static value

  56. //single_ins* single_ins::myc = new single_ins;

  57. /*

  58. 懒汉式的问题在于多线程调用的时候会出现问题,很可能同时建立出多个内存空间,

  59. 而不是单列了。

  60. */

  61. void* main21(void* argc)

  62. {

  63. single_ins* inp = (single_ins*)argc;


  64. inp = single_ins::setp();

  65. inp->setval(10,20);

  66. inp->print();

  67. cout<

  68. return NULL;

  69. }



  70. int main(void)

  71. {

  72. pthread_t tid;

  73. single_ins* a[3] = {NULL};

  74. void* tret[3] = {NULL};

  75. for(int i = 0 ; i<3; i++)

  76. {

  77. pthread_create(&tid,NULL,main21,(void*)a[i]);

  78. //pthread_join(tid, &(tret[i]));

  79. }

  80. sleep(50);

  81. single_ins::pfree();


  82. }

会跑出结果
con begin
con begin
con begin
con end
a:10
b:20
1
0x7fc3880008c0
con end
a:10
b:20
2
0x7fc3800008c0
con end
a:10
b:20
3
0x7fc3840008c0


可以看到
0x7fc3880008c0 0x7fc3800008c0 0x7fc3840008c0
明显是3个不同的内存空间 这就不对了,而且可以看到构造函数
调用了3次
为此我们使用mutex来保护临时

如下:
static single_ins* setp() //函数获得指针值赋给静态成员指针变量
39 {
40 //懒汉式
41 if(myc == NULL)
42 {
43 pthread_mutex_lock(&counter_mutex); //mutex 保护临界区
44 if(myc == NULL) //两次检查
45 {
46 myc = new single_ins;
47 cnt++;
48 }
49 pthread_mutex_unlock(&counter_mutex); //mutex结束
50 }


这样代码如下:

点击(此处)折叠或打开

  1. #include

  2. #include

  3. using namespace std;


  4. pthread_mutex_t counter_mutex = PTHREAD_MUTEX_INITIALIZER;


  5. //单列模式

  6. class single_ins

  7. {

  8. private:

  9. int a;

  10. int b;

  11. single_ins()

  12. {

  13. cout<<"con begin\n";

  14. a= 0;

  15. b= 0;

  16. sleep(10); //故意拖长构造函数执行时间,造成懒汉式多线程问题

  17. cout<<"con end\n";

  18. }

  19. static single_ins* myc;//单例需要一个静态指针

  20. static int cnt;//构造调用次数统计

  21. public:

  22. void setval(const int& a,const int& b)

  23. {

  24. this->a = a;

  25. this->b = b;

  26. }


  27. void print()

  28. {

  29. cout<<"a:"<

  30. cout<<"b:"<

  31. cout<

  32. }



  33. static single_ins* setp() //函数获得指针值赋给静态成员指针变量

  34. {

  35. //懒汉式

  36. if(myc == NULL)

  37. {

  38. pthread_mutex_lock(&counter_mutex); //mutex 保护临界区

  39. if(myc == NULL) //两次检查

  40. {

  41. myc = new single_ins;

  42. cnt++;

  43. }

  44. pthread_mutex_unlock(&counter_mutex); //mutex结束

  45. }

  46. //懒汉式

  47. return myc;

  48. }

  49. static void pfree()

  50. {

  51. if(myc != NULL)

  52. {

  53. delete myc;

  54. myc = NULL;

  55. }

  56. }

  57. };


  58. //懒汉式 init static value

  59. single_ins* single_ins::myc = NULL;

  60. int single_ins::cnt = 0;

  61. //饿汉试 init static value

  62. //single_ins* single_ins::myc = new single_ins;

  63. /*

  64. 懒汉式的问题在于多线程调用的时候会出现问题,很可能同时建立出多个内存空间,

  65. 而不是单列了。

  66. */




  67. void* main21(void* argc)

  68. {

  69. single_ins* inp = (single_ins*)argc;


  70. inp = single_ins::setp();

  71. inp->setval(10,20);

  72. inp->print();

  73. cout<

  74. return NULL;

  75. }



  76. int main(void)

  77. {

  78. pthread_t tid;

  79. single_ins* a[3] = {NULL};

  80. void* tret[3] = {NULL};

  81. for(int i = 0 ; i<3; i++)

  82. {

  83. pthread_create(&tid,NULL,main21,(void*)a[i]);

  84. //pthread_join(tid, &(tret[i]));

  85. }

  86. sleep(50);

  87. single_ins::pfree();


  88. }

跑出的结果如下:

con begin
con end
a:10a:10
b:20
1
0x7f21f40008c0


b:20
1
0x7f21f40008c0
a:10
b:20
1
0x7f21f40008c0


现在就是正常的了。所以懒汉试单例遇到多线程一定要注意,饿汉试没有问题。
当然这是一个小列子而已,线程安全是一个很大的话题,特别需要注意。


以上是"C++如何解决单例懒汉式和多线程问题"这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注行业资讯频道!

0