在《秒杀多线程第十一篇读者写者问题》文章中我们使用事件和一个记录读者个数的变量来解决读者写者问题。问题虽然得到了解决,但代码有点复杂。本篇将介绍一种新方法——读写锁SRWLock来解决这一问题。读 写锁在对资源进行保护的同时,还能区分想要读取资源值的线程(读取者线程)和想要更新资源的线程(写入者线程)。对于读取者线程,读写锁会允许他们并发的 执行。当有写入者线程在占有资源时,读写锁会让其它写入者线程和读取者线程等待。因此用读写锁来解决读者写者问题会使代码非常清晰和简洁。

下面就来看看如何使用读写锁,要注意编译读写锁程序需要VS2008,运行读写锁程序要在Vista或Windows Server2008系统(比这两个更高级的系统也可以)。读写锁的主要函数就五个,分为初始化函数,写入者线程申请和释放函数,读取者线程申请和释放函数,以下是详细的函数使用说明:

第一个 InitializeSRWLock

函数功能:初始化读写锁

函数原型:VOID InitializeSRWLock(PSRWLOCK SRWLock);

函数说明:初始化(没有删除或销毁SRWLOCK的函数,系统会自动清理)

第二个 AcquireSRWLockExclusive

函数功能:写入者线程申请写资源。

函数原型:VOID AcquireSRWLockExclusive(PSRWLOCK SRWLock);

第三个 ReleaseSRWLockExclusive

函数功能:写入者线程写资源完毕,释放对资源的占用。

函数原型:VOID ReleaseSRWLockExclusive(PSRWLOCK SRWLock);

第四个 AcquireSRWLockShared

函数功能:读取者线程申请读资源。

函数原型:VOID AcquireSRWLockShared(PSRWLOCK SRWLock);

第五个 ReleaseSRWLockShared

函数功能:读取者线程结束读取资源,释放对资源的占用。

函数原型:VOID ReleaseSRWLockShared(PSRWLOCK SRWLock);

注意一个线程仅能锁定资源一次,不能多次锁定资源。

使用读写锁精简后的代码如下(代码中变参函数的实现请参阅《C,C++中使用可变参数》,控制台颜色设置请参阅《VC 控制台颜色设置》):

  1. //读者与写者问题继 读写锁SRWLock
  2. #include <stdio.h>
  3. #include <process.h>
  4. #include <windows.h>
  5. //设置控制台输出颜色
  6. BOOL SetConsoleColor(WORD wAttributes)
  7. {
  8. HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
  9. if (hConsole == INVALID_HANDLE_VALUE)
  10. return FALSE;
  11. return SetConsoleTextAttribute(hConsole, wAttributes);
  12. }
  13. const int READER_NUM = 5;  //读者个数
  14. //关键段和事件
  15. CRITICAL_SECTION g_cs;
  16. SRWLOCK          g_srwLock;
  17. //读者线程输出函数(变参函数的实现)
  18. void ReaderPrintf(char *pszFormat, ...)
  19. {
  20. va_list   pArgList;
  21. va_start(pArgList, pszFormat);
  22. EnterCriticalSection(&g_cs);
  23. vfprintf(stdout, pszFormat, pArgList);
  24. LeaveCriticalSection(&g_cs);
  25. va_end(pArgList);
  26. }
  27. //读者线程函数
  28. unsigned int __stdcall ReaderThreadFun(PVOID pM)
  29. {
  30. ReaderPrintf("     编号为%d的读者进入等待中...\n", GetCurrentThreadId());
  31. //读者申请读取文件
  32. AcquireSRWLockShared(&g_srwLock);
  33. //读取文件
  34. ReaderPrintf("编号为%d的读者开始读取文件...\n", GetCurrentThreadId());
  35. Sleep(rand() % 100);
  36. ReaderPrintf(" 编号为%d的读者结束读取文件\n", GetCurrentThreadId());
  37. //读者结束读取文件
  38. ReleaseSRWLockShared(&g_srwLock);
  39. return 0;
  40. }
  41. //写者线程输出函数
  42. void WriterPrintf(char *pszStr)
  43. {
  44. EnterCriticalSection(&g_cs);
  45. SetConsoleColor(FOREGROUND_GREEN);
  46. printf("     %s\n", pszStr);
  47. SetConsoleColor(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
  48. LeaveCriticalSection(&g_cs);
  49. }
  50. //写者线程函数
  51. unsigned int __stdcall WriterThreadFun(PVOID pM)
  52. {
  53. WriterPrintf("写者线程进入等待中...");
  54. //写者申请写文件
  55. AcquireSRWLockExclusive(&g_srwLock);
  56. //写文件
  57. WriterPrintf("  写者开始写文件.....");
  58. Sleep(rand() % 100);
  59. WriterPrintf("  写者结束写文件");
  60. //标记写者结束写文件
  61. ReleaseSRWLockExclusive(&g_srwLock);
  62. return 0;
  63. }
  64. int main()
  65. {
  66. printf("  读者写者问题继 读写锁SRWLock\n");
  67. printf(" -- by MoreWindows( http://blog.csdn.net/MoreWindows ) --\n\n");
  68. //初始化读写锁和关键段
  69. InitializeCriticalSection(&g_cs);
  70. InitializeSRWLock(&g_srwLock);
  71. HANDLE hThread[READER_NUM + 1];
  72. int i;
  73. //先启动二个读者线程
  74. for (i = 1; i <= 2; i++)
  75. hThread[i] = (HANDLE)_beginthreadex(NULL, 0, ReaderThreadFun, NULL, 0, NULL);
  76. //启动写者线程
  77. hThread[0] = (HANDLE)_beginthreadex(NULL, 0, WriterThreadFun, NULL, 0, NULL);
  78. Sleep(50);
  79. //最后启动其它读者结程
  80. for ( ; i <= READER_NUM; i++)
  81. hThread[i] = (HANDLE)_beginthreadex(NULL, 0, ReaderThreadFun, NULL, 0, NULL);
  82. WaitForMultipleObjects(READER_NUM + 1, hThread, TRUE, INFINITE);
  83. for (i = 0; i < READER_NUM + 1; i++)
  84. CloseHandle(hThread[i]);
  85. //销毁关键段
  86. DeleteCriticalSection(&g_cs);
  87. return 0;
  88. }

对比下《秒杀多线程第十一篇读者写者问题》中的代码就可以发现这份代码确实清爽许多了。这个程序用VS2008编译可以通过,但在XP系统下运行会导致报错。

在Win7系统下能够正确的运行,结果如图所示:

最后总结一下读写锁SRWLock

1.读写锁声明后要初始化,但不用销毁,系统会自动清理读写锁。

2.读取者和写入者分别调用不同的申请函数和释放函数。

转---秒杀多线程第十四篇 读者写者问题继 读写锁SRWLock的更多相关文章

  1. 秒杀多线程第十四篇 读者写者问题继 读写锁SRWLock (续)

    java 包实现了读写锁的操作: package com.multithread.readwritelock; import java.util.concurrent.CountDownLatch; ...

  2. 多线程面试题系列(14):读者写者问题继 读写锁SRWLock

    在第十一篇文章中我们使用事件和一个记录读者个数的变量来解决读者写者问题.问题虽然得到了解决,但代码有点复杂.本篇将介绍一种新方法--读写锁SRWLock来解决这一问题.读写锁在对资源进行保护的同时,还 ...

  3. 读者写者问题继 读写锁SRWLock

    在<秒杀多线程第十一篇读者写者问题>文章中我们使用事件和一个记录读者个数的变量来解决读者写者问题.问题虽然得到了解决,但代码有点复杂.本篇将介绍一种新方法--读写锁SRWLock来解决这一 ...

  4. 转---秒杀多线程第十二篇 多线程同步内功心法——PV操作上 (续)

    PV操作的核心就是 PV操作可以同时起到同步与互斥的作用. 1.同步就是通过P操作获取信号量,V操作释放信号量来进行. 2.互斥其实就是,同时操作P操作,结束后进行V操作即可做到. Java上实现PV ...

  5. 多线程 读写锁SRWLock

    在<秒杀多线程第十一篇读者写者问题>文章中我们使用事件和一个记录读者个数的变量来解决读者写者问题.问题虽然得到了解决,但代码有点复杂.本篇将介绍一种新方法——读写锁SRWLock来解决这一 ...

  6. SpringBoot第二十四篇:应用监控之Admin

    作者:追梦1819 原文:https://www.cnblogs.com/yanfei1819/p/11457867.html 版权声明:本文为博主原创文章,转载请附上博文链接! 引言   前一章(S ...

  7. 解剖SQLSERVER 第十四篇 Vardecimals 存储格式揭秘(译)

    解剖SQLSERVER 第十四篇    Vardecimals 存储格式揭秘(译) http://improve.dk/how-are-vardecimals-stored/ 在这篇文章,我将深入研究 ...

  8. 第十四篇 Integration Services:项目转换

    本篇文章是Integration Services系列的第十四篇,详细内容请参考原文. 简介在前一篇,我们查看了SSIS变量,变量配置和表达式管理动态值.在这一篇,我们使用SQL Server数据商业 ...

  9. Python之路【第十四篇】:AngularJS --暂无内容-待更新

    Python之路[第十四篇]:AngularJS --暂无内容-待更新

随机推荐

  1. 20155330 2016-2017-2 《Java程序设计》第三周学习总结

    20155330 2016-2017-2 <Java程序设计>第三周学习总结 教材学习内容总结 学习目标 区分基本类型与类类型 理解对象的生成与引用的关系 掌握String类和数组 理解封 ...

  2. 20155339 2016-2017 2 《Java程序设计》第2周学习总结

    20155339 2016-2017-2 <Java程序设计>第2周学习总结 教材学习内容总结 这周学习了课本的第三章,主要内容是JAVA的基础语法,在这章的学习过程中我发现大部分与c语言 ...

  3. WPF 带水印的密码输入框实现

    原文:WPF 带水印的密码输入框实现 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/BYH371256/article/details/835055 ...

  4. cogs62 [HNOI2004] 宠物收养所

    cogs62 [HNOI2004] 宠物收养所 啦啦啦啦 不维护区间的平衡树题都是树状数组+二分练手题! 不会的参考我的普通平衡树的多种神奇解法之BIT+二分答案 // It is made by X ...

  5. Python不生成HTMLTestRunner报告-转载学习

    1.问题:Python中同一个.py文件中同时用unittest框架和HtmlReport框架后,HtmlReport不被执行. 2.为什么?其实不是HtmlReport不被执行,也不是HtmlRep ...

  6. python-map, reduce, filter, lambda

    目录 lambda表达式 reduce()函数 map()函数 filter()函数 tips:以下使用到的迭代器,可迭代对象,生成器等概念可以参见我的另一篇博客 lambda表达式 主要用于一行写完 ...

  7. win7下配置spark

    1.安装jdk(配置JAVA_HOME,CLASSPATH,path) 2.安装scala(配置SCALA_HOME,path) 3.安装spark Spark的安装非常简单,直接去Download ...

  8. Git + Gerrit 操作备忘

    Git review 作用 可以用来提交代码审核到Gerrit 安装 使用pip 安装 git-review 插件,执行 sudo -H pip install git-review 使用示例 可以参 ...

  9. 【RL系列】从蒙特卡罗方法步入真正的强化学习

    蒙特卡罗方法给我的感觉是和Reinforcement Learning: An Introduction的第二章中Bandit问题的解法比较相似,两者皆是通过大量的实验然后估计每个状态动作的平均收益. ...

  10. ie6下,莫名被复制出一段文字解决

    在IE6下使用浮动可能会出现文字重复的情况. 在IE6下,浮动层之间有注释文字的话,之前那个浮动层的内容文字就有可能遭遇一个“隐形”的复制,但是代码里查看文字可并没有多出来. 看个例子: HTML & ...