读写锁SRWLock

本篇将介绍一种新方法——读写锁SRWLock来解决这一问题。读写锁在对资源进行保护的同时,还能区分想要读取资源值的线程(读取者线程)和想要更新资源的线程(写入者线程)。对于读取者线程,读写锁会允许他们并发的执行。当有写入者线程在占有资源时,读写锁会让其它写入者线程和读取者线程等待。因此用读写锁来解决读者写者问题会使代码非常清晰和简洁。

 

    下面就来看看如何使用读写锁,要注意编译读写锁程序需要VS2008,运行读写锁程序要在VistaWindows 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 控制台颜色设置》):

[cpp]  view plain copy
  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.     //读取文件  
  35.     ReaderPrintf("编号为%d的读者开始读取文件...\n", GetCurrentThreadId());  
  36.     Sleep(rand() % 100);  
  37.     ReaderPrintf(" 编号为%d的读者结束读取文件\n", GetCurrentThreadId());  
  38.   
  39.     //读者结束读取文件  
  40.     ReleaseSRWLockShared(&g_srwLock);  
  41.     return 0;  
  42. }  
  43. //写者线程输出函数  
  44. void WriterPrintf(char *pszStr)  
  45. {  
  46.     EnterCriticalSection(&g_cs);  
  47.     SetConsoleColor(FOREGROUND_GREEN);  
  48.     printf("     %s\n", pszStr);  
  49.     SetConsoleColor(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);  
  50.     LeaveCriticalSection(&g_cs);  
  51. }  
  52. //写者线程函数  
  53. unsigned int __stdcall WriterThreadFun(PVOID pM)  
  54. {  
  55.     WriterPrintf("写者线程进入等待中...");  
  56.     //写者申请写文件  
  57.     AcquireSRWLockExclusive(&g_srwLock);  
  58.           
  59.     //写文件  
  60.     WriterPrintf("  写者开始写文件.....");  
  61.     Sleep(rand() % 100);  
  62.     WriterPrintf("  写者结束写文件");  
  63.   
  64.     //标记写者结束写文件  
  65.     ReleaseSRWLockExclusive(&g_srwLock);  
  66.     return 0;  
  67. }  
  68. int main()  
  69. {  
  70.     printf("  读者写者问题继 读写锁SRWLock\n");  
  71.     printf(" -- by MoreWindows( http://blog.csdn.net/MoreWindows ) --\n\n");  
  72.   
  73.     //初始化读写锁和关键段  
  74.     InitializeCriticalSection(&g_cs);  
  75.     InitializeSRWLock(&g_srwLock);  
  76.   
  77.     HANDLE hThread[READER_NUM + 1];  
  78.     int i;  
  79.     //先启动二个读者线程  
  80.     for (i = 1; i <= 2; i++)  
  81.         hThread[i] = (HANDLE)_beginthreadex(NULL, 0, ReaderThreadFun, NULL, 0, NULL);  
  82.     //启动写者线程  
  83.     hThread[0] = (HANDLE)_beginthreadex(NULL, 0, WriterThreadFun, NULL, 0, NULL);  
  84.     Sleep(50);  
  85.     //最后启动其它读者结程  
  86.     for ( ; i <= READER_NUM; i++)  
  87.         hThread[i] = (HANDLE)_beginthreadex(NULL, 0, ReaderThreadFun, NULL, 0, NULL);  
  88.     WaitForMultipleObjects(READER_NUM + 1, hThread, TRUE, INFINITE);  
  89.     for (i = 0; i < READER_NUM + 1; i++)  
  90.         CloseHandle(hThread[i]);  
  91.   
  92.     //销毁关键段  
  93.     DeleteCriticalSection(&g_cs);  
  94.     return 0;  
  95. }  

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

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

 

 

最后总结一下读写锁SRWLock

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

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

3.  只能在Vista和Server 2008以上系统中才能使用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值