在Win32下用C++ 实现多线程读写锁

nutxzycftqg 2012-02-17 03:57:13
加精
读写锁实际是一种特殊的自旋锁,它把对共享资源的访问者划分成读者和写者,读者只对共享资源进行读访问,写者则需要对共享资源进行写操作。这种锁相对于自旋锁而言,能提高并发性,因为在多处理器系统中,它允许同时有多个读者来访问共享资源,最大可能的读者数为实际的逻辑CPU数。写者是排他性的,一个读写锁同时只能有一个写者或多个读者(与CPU数相关),但不能同时既有读者又有写者。

现在Win32的API,用C++实现自己的读写锁。这组API包括:CreateMutex,CreateEvent,WaitForSingleObject,WaitForMultipleObjects,ResetEvent,ReleaseMutex,SetEvent,CloseHandle。以下代码在VS2005下,已经编译通过。

RWLockImpl.h

01.#ifndef _RWLockImpl_Header
02.#define _RWLockImpl_Header
03.
04.#include
05.#include
06.#include
07.#include
08.
09.using namespace std;
10.
11./*
12. 读写锁允许当前的多个读用户访问保护资源,但只允许一个写读者访问保护资源
13.*/
14.
15.//-----------------------------------------------------------------
16.class CRWLockImpl
17.{
18.protected:
19. CRWLockImpl();
20. ~CRWLockImpl();
21. void ReadLockImpl();
22. bool TryReadLockImpl();
23. void WriteLockImpl();
24. bool TryWriteLockImpl();
25. void UnlockImpl();
26.
27.private:
28. void AddWriter();
29. void RemoveWriter();
30. DWORD TryReadLockOnce();
31.
32. HANDLE m_mutex;
33. HANDLE m_readEvent;
34. HANDLE m_writeEvent;
35. unsigned m_readers;
36. unsigned m_writersWaiting;
37. unsigned m_writers;
38.};
39.
40.//-----------------------------------------------------------------
41.
42.class CMyRWLock: private CRWLockImpl
43.{
44.public:
45.
46. //创建读/写锁
47. CMyRWLock(){};
48.
49. //销毁读/写锁
50. ~CMyRWLock(){};
51.
52. //获取读锁
53. //如果其它一个线程占有写锁,则当前线程必须等待写锁被释放,才能对保护资源进行访问
54. void ReadLock();
55.
56. //尝试获取一个读锁
57. //如果获取成功,则立即返回true,否则当另一个线程占有写锁,则返回false
58. bool TryReadLock();
59.
60. //获取写锁
61. //如果一个或更多线程占有读锁,则必须等待所有锁被释放
62. //如果相同的一个线程已经占有一个读锁或写锁,则返回结果不确定
63. void WriteLock();
64.
65. //尝试获取一个写锁
66. //如果获取成功,则立即返回true,否则当一个或更多其它线程占有读锁,返回false
67. //如果相同的一个线程已经占有一个读锁或写锁,则返回结果不确定
68. bool TryWriteLock();
69.
70. //释放一个读锁或写锁
71. void Unlock();
72.
73.private:
74. CMyRWLock(const CMyRWLock&);
75. CMyRWLock& operator = (const CMyRWLock&);
76.};
77.
78.inline void CMyRWLock::ReadLock()
79.{
80. ReadLockImpl();
81.}
82.
83.inline bool CMyRWLock::TryReadLock()
84.{
85. return TryReadLockImpl();
86.}
87.
88.inline void CMyRWLock::WriteLock()
89.{
90. WriteLockImpl();
91.}
92.
93.inline bool CMyRWLock::TryWriteLock()
94.{
95. return TryWriteLockImpl();
96.}
97.
98.inline void CMyRWLock::Unlock()
99.{
100. UnlockImpl();
101.}
102.
103.
104.#endif
RWLockImpl.cpp
01.#include "RWLockImpl.h"
02.
03.CRWLockImpl::CRWLockImpl(): m_readers(0), m_writersWaiting(0), m_writers(0)
04.{
05. m_mutex = CreateMutex(NULL, FALSE, NULL);
06. if (m_mutex == NULL)
07. cout<<"cannot create reader/writer lock"<<endl;
08.
09. m_readEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
10. if (m_readEvent == NULL)
11. cout<<"cannot create reader/writer lock"<<endl;
12.
13. m_writeEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
14. if (m_writeEvent == NULL)
15. cout<<"cannot create reader/writer lock"<<endl;
16.}
17.
18.CRWLockImpl::~CRWLockImpl()
19.{
20. CloseHandle(m_mutex);
21. CloseHandle(m_readEvent);
22. CloseHandle(m_writeEvent);
23.}
24.
25.inline void CRWLockImpl::AddWriter()
26.{
27. switch (WaitForSingleObject(m_mutex, INFINITE))
28. {
29. case WAIT_OBJECT_0:
30. if (++m_writersWaiting == 1)
31. ResetEvent(m_readEvent);
32. ReleaseMutex(m_mutex);
33. break;
34. default:
35. cout<<"cannot lock reader/writer lock"<<endl;
36. }
37.}
38.
39.inline void CRWLockImpl::RemoveWriter()
40.{
41. switch (WaitForSingleObject(m_mutex, INFINITE))
42. {
43. case WAIT_OBJECT_0:
44. if (--m_writersWaiting == 0 && m_writers == 0)
45. SetEvent(m_readEvent);
46. ReleaseMutex(m_mutex);
47. break;
48. default:
49. cout<<"cannot lock reader/writer lock"<<endl;
50. }
51.}
52.
53.void CRWLockImpl::ReadLockImpl()
54.{
55. HANDLE h[2];
56. h[0] = m_mutex;
57. h[1] = m_readEvent;
58. switch (WaitForMultipleObjects(2, h, TRUE, INFINITE))
59. {
60. case WAIT_OBJECT_0:
61. case WAIT_OBJECT_0 + 1:
62. ++m_readers;
63. ResetEvent(m_writeEvent);
64. ReleaseMutex(m_mutex);
65. assert(m_writers == 0);
66. break;
67. default:
68. cout<<"cannot lock reader/writer lock"<<endl;
69. }
70.}
71.
72.bool CRWLockImpl::TryReadLockImpl()
73.{
74. for (;;)
75. {
76. if (m_writers != 0 || m_writersWaiting != 0)
77. return false;
78.
79. DWORD result = TryReadLockOnce();
80. switch (result)
81. {
82. case WAIT_OBJECT_0:
83. case WAIT_OBJECT_0 + 1:
84. return true;
85. case WAIT_TIMEOUT:
86. continue;
87. default:
88. cout<<"cannot lock reader/writer lock"<<endl;
89. }
90. }
91.}
92.
93.void CRWLockImpl::WriteLockImpl()
94.{
95. AddWriter();
96. HANDLE h[2];
97. h[0] = m_mutex;
98. h[1] = m_writeEvent;
99. switch (WaitForMultipleObjects(2, h, TRUE, INFINITE))
100. {
101. case WAIT_OBJECT_0:
102. case WAIT_OBJECT_0 + 1:
103. --m_writersWaiting;
104. ++m_readers;
105. ++m_writers;
106. ResetEvent(m_readEvent);
107. ResetEvent(m_writeEvent);
108. ReleaseMutex(m_mutex);
109. assert(m_writers == 1);
110. break;
111. default:
112. RemoveWriter();
113. cout<<"cannot lock reader/writer lock"<<endl;
114. }
115.}
116.
117.bool CRWLockImpl::TryWriteLockImpl()
118.{
119. AddWriter();
120. HANDLE h[2];
121. h[0] = m_mutex;
122. h[1] = m_writeEvent;
123. switch (WaitForMultipleObjects(2, h, TRUE, 1))
124. {
125. case WAIT_OBJECT_0:
126. case WAIT_OBJECT_0 + 1:
127. --m_writersWaiting;
128. ++m_readers;
129. ++m_writers;
130. ResetEvent(m_readEvent);
131. ResetEvent(m_writeEvent);
132. ReleaseMutex(m_mutex);
133. assert(m_writers == 1);
134. return true;
135. case WAIT_TIMEOUT:
136. RemoveWriter();
137. default:
138. RemoveWriter();
139. cout<<"cannot lock reader/writer lock"<<endl;
140. }
141. return false;
142.}
143.
144.void CRWLockImpl::UnlockImpl()
145.{
146. switch (WaitForSingleObject(m_mutex, INFINITE))
147. {
148. case WAIT_OBJECT_0:
149. m_writers = 0;
150. if (m_writersWaiting == 0) SetEvent(m_readEvent);
151. if (--m_readers == 0) SetEvent(m_writeEvent);
152. ReleaseMutex(m_mutex);
153. break;
154. default:
155. cout<<"cannot unlock reader/writer lock"<<endl;
156. }
157.}
158.
159.DWORD CRWLockImpl::TryReadLockOnce()
160.{
161. HANDLE h[2];
162. h[0] = m_mutex;
163. h[1] = m_readEvent;
164. DWORD result = WaitForMultipleObjects(2, h, TRUE, 1);
165. switch (result)
166. {
167. case WAIT_OBJECT_0:
168. case WAIT_OBJECT_0 + 1:
169. ++m_readers;
170. ResetEvent(m_writeEvent);
171. ReleaseMutex(m_mutex);
172. assert(m_writers == 0);
173. return result;
174. case WAIT_TIMEOUT:
175. default:
176. cout<<"cannot lock reader/writer lock"<<endl;
177. }
178. return result;
179.}
180.
下边是测试代码
01.// MyRWLockWin32.cpp : 定义控制台应用程序的入口点。
02.//
03.
04.#include "RWLockImpl.h"
05.
06.//创建一个读写锁对象
07.CMyRWLock g_myRWLock;
08.volatile int g_counter = 0;
09.
10.//线程函数
11.unsigned int __stdcall StartThread(void *pParam)
12.{
13. int lastCount = 0;
14. for (int i = 0; i < 10000; ++i)
15. {
16. g_myRWLock.ReadLock();
17. lastCount = g_counter;
18. //在读锁域,两个线程不断循环交替访问全局变量g_counter
19. for (int k = 0; k < 100; ++k)
20. {
21. if (g_counter != lastCount)
22. cout<<"the value of g_counter has been updated."<<endl;
23. Sleep(0);
24. }
25. g_myRWLock.Unlock();
26.
27.
28. g_myRWLock.WriteLock();
29. //在写锁域,只有一个线程可以修改全局变量g_counter的值
30. for (int k = 0; k < 100; ++k)
31. {
32. --g_counter;
33. Sleep(0);
34. }
35. for (int k = 0; k < 100; ++k)
36. {
37. ++g_counter;
38. Sleep(0);
39. }
40. ++g_counter;
41. if (g_counter <= lastCount)
42. cout<<"the value of g_counter is error."<<endl;
43. g_myRWLock.Unlock();
44. }
45.
46. return (unsigned int)0;
47.}
48.
49.int main(int argc, char* argv[])
50.{
51. HANDLE hThread1, hThread2;
52. unsigned int uiThreadId1, uiThreadId2;
53.
54. //创建两个工作线程
55. hThread1 = (HANDLE)_beginthreadex(NULL, 0, &StartThread, (void *)NULL, 0, &uiThreadId1);
56. hThread2 = (HANDLE)_beginthreadex(NULL, 0, &StartThread, (void *)NULL, 0, &uiThreadId2);
57.
58. //等待线程结束
59. DWORD dwRet = WaitForSingleObject(hThread1,INFINITE);
60. if ( dwRet == WAIT_TIMEOUT )
61. {
62. TerminateThread(hThread1,0);
63. }
64. dwRet = WaitForSingleObject(hThread2,INFINITE);
65. if ( dwRet == WAIT_TIMEOUT )
66. {
67. TerminateThread(hThread2,0);
68. }
69.
70. //关闭线程句柄,释放资源
71. CloseHandle(hThread1);
72. CloseHandle(hThread2);
73.
74. assert (g_counter == 20000);
75.
76. system("pause");
77. return 0;
78.}

...全文
1998 36 打赏 收藏 转发到动态 举报
写回复
用AI写文章
36 条回复
切换为时间正序
请发表友善的回复…
发表回复
onlywsk 2012-02-23
  • 打赏
  • 举报
回复
请教怎样可以获得积分去下载呀
ksharp 2012-02-22
  • 打赏
  • 举报
回复
前阵子也在研究多线程,发现系统上某些API不正常工作,当时纠结了好久。
jueying3 2012-02-22
  • 打赏
  • 举报
回复
人才 ……哈哈哈 哈哈好
liu20072637 2012-02-22
  • 打赏
  • 举报
回复
拷下来试试看~
dfasri 2012-02-22
  • 打赏
  • 举报
回复
楼主说的, 是 共享读, 互斥写 的原子锁类型.
在DELPHI下面, 有一个MutilReadExcludeWrite类. 楼主可以参考一下.
yanyuchonglou 2012-02-22
  • 打赏
  • 举报
回复
看完后,我无耻地笑了。

俺用多线程都管它叫IPC的,同步是融在过程里的,从不装模作样地弄个OO出来。
寒沙胜雪 2012-02-21
  • 打赏
  • 举报
回复
这个 在孙鑫的后面进程管理课程里面有讲吧。 好久没用 忘记了。
kb5706 2012-02-21
  • 打赏
  • 举报
回复
牛人!!菜鸟膜拜!!!
viphj 2012-02-21
  • 打赏
  • 举报
回复
GOOD,GOOD,SO GOOD
半曲恋江南 2012-02-21
  • 打赏
  • 举报
回复
长啊!不过还好!
noodle123 2012-02-20
  • 打赏
  • 举报
回复
那么长的代码我都没心看,不过肯定不错,顶一下。
叶子 2012-02-20
  • 打赏
  • 举报
回复
围观精华帖!
FounderSG 2012-02-20
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 shiming1980 的回复:]
TuroboC 2,无法通过
[/Quote]
说得太对了。
郁闷阳光 2012-02-19
  • 打赏
  • 举报
回复
牛人啊
nettman 2012-02-19
  • 打赏
  • 举报
回复
关注下!
kobe990 2012-02-19
  • 打赏
  • 举报
回复
的广泛的风格大方
kobe990 2012-02-19
  • 打赏
  • 举报
回复
sdfsdfdsfsdf
cdcjk 2012-02-19
  • 打赏
  • 举报
回复
我是初学者
Carchy 2012-02-18
  • 打赏
  • 举报
回复
靠,没看懂哦,
HYH_HENG 2012-02-18
  • 打赏
  • 举报
回复
挺牛B啊
加载更多回复(9)
书籍目录: 第1篇 Visual C#基础编程实例 实例1 C#经典程序--Hello World 实例2 C#的简单输入输出(I/O) 实例3 C#的复杂输入输出(I/O) 实例4 通信录管理与维护 实例5 文件与目录管理 实例6 用户界面上的“Hello,World!” 实例7 组件化“Welcome”程序 实例8 网络上的“Hello World” 实例9 Ref、Out与Params描述符的应用 实例10 C#自动内存管理的应用 实例11 一个有趣栈类的实现 实例12 垃圾收集器管理与应用 实例13 垃圾收集器算法控制与使用 实例14 调用栈记录异常点 实例15 使用C#异常的栈跟踪 实例16 运行期间检测变量类型 实例17 常用值类型的原型定义 实例18 打印杨辉三角形 实例19 比较学生信息 实例20 获取车辆信息 实例21 简单角色类游戏的制作 实例22 旅馆住宿登记情况表制作 实例23 长命名空间的应用 实例24 文件特征计数 实例25 文本框输入数据的验证 第2篇 Visual C#中级编程实例 实例26 窗体背景颜色动态变化 实例27 C#属性及应用 实例28 C#属性Metadata的管理与应用 实例29 使用Context属性创建CallThreshold Service 实例30 使用应用程序域 实例31 创建C#组件与客户应用程序 实例32 用OpenFileDialog类浏览或打开文件 实例33 在C#程序中获得Win32 API 实例34 从C#中调用COM组件 实例35 在C#程序中修改HTML文件标题 实例36 下载Web页面 实例37 创建多线程应用程序 实例38 多线程的多次加载 实例39 单个线程同步运行 实例40 多线程同步运行 实例41 线程Thread Relative Static跟踪与实现 实例42 线程池(ThreadPool)的应用 实例43 多线程互斥运行 实例44 多线程时钟应用程序 实例45 监视多线程 实例46 防止多线程应用程序死锁 实例47 文件同步操作与应用 实例48 在COM程序设计中使用.NET组件 实例49 文件异步操作与多处理器系统 实例50 获取网络主机IP地址 实例51 C#对话信息框的应用 实例52 在C#中快速调用Windows API 实例53 摄氏温度与华氏温度间相互转换(1) 实例54 摄氏温度与华氏温度间相互转换(2) 实例55 使用FileSystemWatcher组件监视Web服务器 实例56 由颜色名字产生对应颜色 实例57 使用索引指示器分析域名 实例58 C#版本的PingC 实例59 DNS客户程序 实例60 一个有趣的DOS实用程序 实例61 代表元基本应用 实例62 有趣的事件代表元 实例63 随机连续偶数发生事件处理 实例64 有趣的列表框窗体 实例65 数学函数应用 第3篇 Visual C#高级编程实例 实例66 文件夹中的文件列表 实例67 读写文本文件 实例68 读写二进制文件 实例69 显示系统日期与时间(1) 实例70 显示差值的日期与时间(2) 实例71 时钟发生器应用 实例72 在.NET程序设计中使用ATL 实例73 浏览Internet文件 实例74 在C#应用程序中打开浏览器 实例75 显示Internet文件信息 实例76 Puzzle游戏 实例77 MDI窗体菜单设计(1) 实例78 MDI窗体菜单设计(2) 实例79 创建一个C#编辑器 实例80 网络端口扫描器 实例81 深入WinForms-地址簿应用(1) 实例82 深入WinForms--Image Viewer应用程序(2) 实例83 开饭时间提醒器(Meal Reminder) 实例84 服务器端C#实例 实例85 数字时钟设计技术 实例86 自动编译C#程序AutoCompiler 实例87 使用C#与ASP+编写File Uploder 实例88 访问注册表中的硬件信息 实例89 设置“开始”菜单 实例90 在“新建”中添加自己的文件类型 实例91 显示Exchange软件的客户名称 实例92 读取Windows注册表信息 实例93 自定义AboutBox组件 实例94 自定义控件及应用 实例95 Java与C#混合编程的应用 实例96 C#与C++混合编程的应用 实例97 C#与VB混合编程的应用 实例98 C#组件与C#客户程序编程的应用 实例99 C#与XML联合应用XMLHelper 实例100 在C#中部署应用

566

社区成员

发帖
与我相关
我的任务
社区描述
英特尔® 边缘计算,聚焦于边缘计算、AI、IoT等领域,为开发者提供丰富的开发资源、创新技术、解决方案与行业活动。
社区管理员
  • 英特尔技术社区
  • shere_lin
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧