OnTheWay2012
埋葬昨天的我,迎来重生的我!
C++博客
首页
新文章
新随笔
聚合
管理
posts - 15, comments - 89, trackbacks - 0
一种线程安全的单例模式实现方式
昨天写了一篇随笔,里面提到了单例模式,本来没有想多说单例模式,可是有人回复说让我先看看线程安全再来谈设计模式。
今天闲来无事就随便写了个线程安全的设计模式,具体代码如下:
1
#include
<
iostream
>
2
#include
<
vector
>
3
#include
<
bitset
>
4
#include
<
assert.h
>
5
#include
<
Windows.h
>
6
#include
<
process.h
>
7
8
using
namespace
std;
9
10
class
CSingleton
11
{
12
private
:
13
class
CAssistForSingleton
14
{
15
private
:
16
CRITICAL_SECTION m_cs;
17
18
public
:
19
CAssistForSingleton()
20
{
21
InitializeCriticalSection(
&
m_cs);
22
}
23
24
~
CAssistForSingleton()
25
{
26
DeleteCriticalSection(
&
m_cs);
27
}
28
29
public
:
30
void
Lock()
31
{
32
EnterCriticalSection(
&
m_cs);
33
}
34
35
void
UnLock()
36
{
37
LeaveCriticalSection(
&
m_cs);
38
}
39
}
;
40
41
private
:
42
static
CAssistForSingleton m_refSycObj;
43
static
CSingleton
*
m_pInstance;
44
45
static
int
m_nData;
46
47
private
:
48
CSingleton()
49
{
50
51
}
52
53
public
:
54
static
CSingleton
*
GetInstatnce()
55
{
56
m_refSycObj.Lock();
57
if
(NULL
==
m_pInstance)
58
{
59
m_pInstance
=
new
CSingleton;
60
cout
<<
"
new CSingleton
"
<<
endl;
61
}
62
m_refSycObj.UnLock();
63
64
return
m_pInstance;
65
}
66
67
public
:
68
static
int
GetData()
69
{
70
return
m_nData;
71
}
72
73
static
void
SetData(
int
nData)
74
{
75
m_refSycObj.Lock();
76
m_nData
=
nData;
77
m_refSycObj.UnLock();
78
}
79
}
;
80
81
CSingleton::CAssistForSingleton CSingleton::m_refSycObj
=
CSingleton::CAssistForSingleton();
82
CSingleton
*
CSingleton::m_pInstance
=
NULL;
83
int
CSingleton::m_nData
=
0
;
84
85
unsigned
int
WINAPI ThreadFun(
void
*
)
86
{
87
cout
<<
"
Launcher Thread
"
<<
endl;
88
89
for
(
int
i
=
0
; i
<
99999999
; i
++
)
90
{
91
CSingleton
*
pSingl
=
CSingleton::GetInstatnce();
92
if
(NULL
!=
pSingl)
93
{
94
pSingl
->
SetData(i);
95
}
96
97
Sleep(
500
);
98
}
99
100
return
0
;
101
}
102
103
int
main(
int
argv,
char
*
argc[])
104
{
105
uintptr_t HandleThread[
10
];
106
unsigned
int
nThreadId
=
0
;
107
for
(
int
i
=
0
; i
<
10
; i
++
)
108
{
109
HandleThread[i]
=
_beginthreadex(NULL,
0
, ThreadFun, NULL,
0
,
&
nThreadId);
110
}
111
112
WaitForMultipleObjects(
10
, (
const
HANDLE
*
)HandleThread, TRUE, INFINITE);
113
114
return
0
;
115
}
116
117
以上就是我的实现,有什么问题欢迎批评指针。
posted on 2010-05-21 09:52
OnTheWay
阅读(5725)
评论(15)
编辑
收藏
引用
所属分类:
软件设计
FeedBack:
#
re: 一种线程安全的单例模式实现方式
2010-05-21 10:15 |
战魂小筑
1. 可以不用单件, 程序开始时全局new出来, 以后不用锁,直接用就好.
2. 既然全是静态数据, 还需要用Singleton呢?
3. 用Interlock会更高效
回复
更多评论
#
re: 一种线程安全的单例模式实现方式
2010-05-21 10:52 |
GunsNRose
之前看过一个,建议将构造弄成 私有的,生成实例由 GetInstatnce来做
别人new是new不了的
回复
更多评论
#
re: 一种线程安全的单例模式实现方式
2010-05-21 15:37 |
OwnWaterloo
依然不是线程安全的。
回复
更多评论
#
re: 一种线程安全的单例模式实现方式
2010-05-21 21:02 |
ccsdu2009
去看看ZThread中的单件吧
以前的话我会推荐loki的
但是现在归纳绝那个太复杂了
回复
更多评论
#
re: 一种线程安全的单例模式实现方式[未登录]
2010-05-22 07:17 |
OnTheWay
@OwnWaterloo
您好,首先感谢您对本随笔的关注。恳请您说详细一点,我不太明白哪些地方还不是线程安全的。
回复
更多评论
#
re: 一种线程安全的单例模式实现方式
2010-05-22 08:57 |
OwnWaterloo
@OnTheWay
class S
{
S() { ... }
~S(); { ... }
S(S const&);
S& operator=(S const&S);
public:
static S& instance()
{
static S s;
return s;
}
};
你认为C++(C++03)是否保证S::instance是线程安全的?
如果是, 请说明理由。
如果C++不保证, 是否应该将S::instance作成线程安全的?
回复
更多评论
#
re: 一种线程安全的单例模式实现方式
2010-05-22 09:00 |
OwnWaterloo
@OnTheWay
再来一种:
class S
{
// ctor, copy, dtor, assignment
static S s_;
public:
S& instance() { return s_; }
};
S S::s_;
同样是上面的问题。
回复
更多评论
#
re: 一种线程安全的单例模式实现方式[未登录]
2010-05-22 09:12 |
OnTheWay
@OwnWaterloo
我觉得不是线程安全的,原因如下:
在你给出的代码中类S中的函数(虽然现在我还没有想不出这种函数)可能不是线程安全的。
我的MSN是wwj_5_209@163.com,能否加我一下,我们讨论一下。
回复
更多评论
#
re: 一种线程安全的单例模式实现方式
2010-05-22 14:59 |
匿名
@OwnWaterloo
与博文中的不是一回事。
回复
更多评论
#
re: 一种线程安全的单例模式实现方式
2010-05-22 19:08 |
OwnWaterloo
@OnTheWay
注意两种需要运行时初始化的静态对象, s和s_。
前者的初始化时机C++有保证, 但不保证多线程安全。
后者的初始化时机C++只保证同一翻译单元内中有顺序。
再看static CAssistForSingleton m_refSycObj;
这就属于第2种。
下面的情况有发生的可能性:
1. 另一翻译单元的静态对象先于m_refSycObj被初始化
2. 在它初始化时访问了CSingleton *GetInstatnce()
此时就访问了一个"未初始化"的临界区。
这已经是bug。
再有, 如果有下列情况:
1. 一些先于m_refSycObj初始化的代码开启了线程
2. 多个线程在m_refSycObj初始化前访问CSingleton *GetInstatnce()
一个未初始化的m_refSycObj根本不能用于同步。
所以, 上面的第1个问题: 这样做不是多线程安全的。
而静态对象在构造时启动线程的情况并不多, 所以并不一定需要将s_作成多线程安全。
例如boost就是这样, 要求在进入main之前, 是不许有两条以上的执行路径去访问。
这就是第2个问题。
如果需要完全的多线程安全:
1. 使用once_initial函数(pthread或者win6有提供)
2. 使用"可以静态初始化"的锁, 比如pthread_mutex_t就可以
或者自己使用一个spinlock也行。
我没有msn…… 用gmail的同名邮箱。
回复
更多评论
#
re: 一种线程安全的单例模式实现方式
2010-05-22 19:09 |
OwnWaterloo
@匿名
知道什么叫"举一反三"吗?
回复
更多评论
#
re: 一种线程安全的单例模式实现方式[未登录]
2010-05-22 22:50 |
~
个人一点随想:我觉得应该从实际应用的逻辑上来进行线程安全的分析,并根据现实情况的分析避免不必要的加解锁操作。某些代码只是一种理想化的东西。现实中有太多比SetData复杂的逻辑。而且也不一定需要加锁。当然从你这个代码看,GetInstatnce当然是正确的哈。
回复
更多评论
#
re: 一种线程安全的单例模式实现方式
2010-05-27 00:02 |
GunsNRose
傻逼实现也好意思贴出来?丢人现眼
回复
更多评论
#
re: 一种线程安全的单例模式实现方式[未登录]
2010-05-27 08:56 |
cppexplore
@OnTheWay
c++里的线程安全单例应该是典型的双重检测.
文中如此实现的话, 每次调用GetInstatnce都要涉及到加锁操作, 估计没人愿意调用.
回复
更多评论
#
re: 一种线程安全的单例模式实现方式
2010-10-30 14:27 |
杨云召
没有用volatile,显然不是线程安全的
回复
更多评论
刷新评论列表
只有注册用户
登录
后才能发表评论。
【推荐】100%开源!大型工业跨平台软件C++源码提供,建模,组态!
网站导航:
博客园
IT新闻
BlogJava
博问
Chat2DB
管理
<
2010年12月
>
日
一
二
三
四
五
六
28
29
30
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
1
2
3
4
5
6
7
8
常用链接
我的随笔
我的评论
我参与的随笔
留言簿
(4)
给我留言
查看公开留言
查看私人留言
随笔分类
C、C++(2)
操作系统(Windows、Linux、Unix)
读书笔记
个人感悟(4)
面经 (4)
软件设计(1)
数据库
算法(3)
线程、进程
英语
杂项
转载
随笔档案
2011年1月 (1)
2010年12月 (2)
2010年11月 (1)
2010年6月 (1)
2010年5月 (6)
2010年4月 (1)
2010年3月 (3)
友情连接
搜索
最新评论
1. re: 对“随笔”所写的一篇文章《链表实验》的一点看法
评论内容较长,点击标题查看
--陈梓瀚(vczh)
2. re: 对“随笔”所写的一篇文章《链表实验》的一点看法
谢谢咯,呵呵。我喜欢这代码风格,向你学习
--あ维wêiセ
3. re: 一种基于引用计数机制的智能指针实现
把A *p = new A();这句换成A p;不行吗?
--叫我老王吧
4. re: 一种基于引用计数机制的智能指针实现
Boost 里面有,在C++ TR1 里面也已经有这种指针(就是来自Boost)
--Phuehvk
5. re: 一种基于引用计数机制的智能指针实现[未登录]
比较讨厌这种引用计数指针的使用,一旦使用就意味这在所有的函数参数中必须使用指针引用或者值拷贝,一旦某些函数要求用裸指针,就可能引发问题。
--hdqqq
阅读排行榜
1. 一道面试题(求一个unsigned int 数的二进制表示中有多少个1?)(6142)
2. 一种线程安全的单例模式实现方式(5725)
3. 一种基于引用计数机制的智能指针实现(2894)
4. 不要把类的外衣脱下来,让类的美丽消失于无形(2768)
5. 几道面试题,有的做出来了,有的不会做,请大家指教(2601)
评论排行榜
1. 一道面试题(求一个unsigned int 数的二进制表示中有多少个1?)(15)
2. 一种线程安全的单例模式实现方式(15)
3. 几道面试题,有的做出来了,有的不会做,请大家指教(14)
4. 令人气愤的现象(13)
5. 不要把类的外衣脱下来,让类的美丽消失于无形(9)