在《秒杀多线程第十一篇读者写者问题》文章中我们使用事件和一个记录读者个数的变量来解决读者写者问题。问题虽然得到了解决,但代码有点复杂。本篇将介绍一种新方法——读写锁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. GridView中加入//实现分页

    要在GridView中加入//实现分页 AllowPaging="true" PageSize="10" // 分页时触发的事件 protectedvoid g ...

  2. HBase第二章 基本API

    1.pom.xml <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www ...

  3. 四、Django设置相关

    1.全局设置 setttings文件 import os import sys # Build paths inside the project like this: os.path.join(BAS ...

  4. activeX 打包

    原文 http://www.docin.com/p-409284488.html CAB打包文档说明 文档目的 本文档的目的在于说明将ocx和dll以及相关的文件打包成一个CAB包,以便在网页下调用o ...

  5. iframe ie低版本 横向滚动条的解决办法

    吐槽下百度,在百度搜这个问题都是渣渣,谷歌直接就出来了,记录一下 设置Frame时,有一属性是scrolling="yes/no/auto",IE6的mozilla都支持,或许对a ...

  6. JMeter测试WebSocket的经验总结

    最近有一个微信聊天系统的项目需要性能测试,既然是测试微信聊天,肯定绕不开websocket接口的测试,首选工具是Jmeter,网上能搜到现成的方法,但是网上提供的jar包往往不是最新的,既然是用最新版 ...

  7. socket_tcp协议_loadrunner测试

    1.lrs_create_socket("socket0", "TCP", "RemoteHost=127.0.0.1:8888", Lrs ...

  8. centos 6.5 双网卡 上网 virtualbox nat hostonly

    虚拟机两张网卡:分别调成NAT(eth0)和host only(eht1)模式. nat的网卡不用设置,host only网卡调为(vi /etc/sysconfig/network-scripts/ ...

  9. linux ——使用find如何快速替换所有相同参数

    在生成环境上有时候需要大规模修改某一配置里的参数,但是该参数存在多个地方,比如IP地址 端口 项目名等,特别是项目名称混乱想统一 find  /项目地址 -type f |xargs grep &qu ...

  10. Valgrind 简单用法

    有时需要给自己写的小程序做个简单的 benchmark,查看内存使用情况和运行时间.这时可以试试 valgrind. Ubuntu 下安装很简单: sudo apt-get update sudo a ...