博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【多线程】学习12
阅读量:7118 次
发布时间:2019-06-28

本文共 3352 字,大约阅读时间需要 11 分钟。

以下内容来自:

 

  前面我们使用和一个记录读者个数的变量来解决读者写者问题。问题虽然得到了解决,但代码有点复杂。本篇将介绍一种新方法——读写锁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);

 

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

 

使用读写锁精简后的代码如下:

#include 
#include
#include
BOOL SetConsoleColor(WORD wAttributes){ HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); if(hConsole == INVALID_HANDLE_VALUE) return FALSE; return SetConsoleTextAttribute(hConsole, wAttributes);}const int READER_NUM = 5; //读者个数//关键段和事件CRITICAL_SECTION g_cs;SRWLOCK g_srwLock;//读者线程输出函数void ReaderPrintf(char *pszFormat, ...){ va_list pArgList; va_start(pArgList, pszFormat); EnterCriticalSection(&g_cs); //为了颜色显示的统一 读者和写者不可同时输出信息 vfprintf(stdout, pszFormat, pArgList); LeaveCriticalSection(&g_cs); va_end(pArgList);}//读者线程函数unsigned int __stdcall ReaderThreadFun(PVOID pM){ ReaderPrintf(" 编号为%d的读者进入等待中...\n", GetCurrentThreadId()); //等待写者完成 AcquireSRWLockShared(&g_srwLock); Sleep(10); //读取文件 ReaderPrintf("编号为%d的读者开始读取文件...\n", GetCurrentThreadId()); Sleep(rand() % 100); //结束阅读,读者个数减少,空位增加 ReaderPrintf(" 编号为%d的读者结束读取文件\n", GetCurrentThreadId()); ReleaseSRWLockShared(&g_srwLock); return 0;}//写者线程输出函数void WriterPrintf(char *pszStr){ EnterCriticalSection(&g_cs); SetConsoleColor(FOREGROUND_GREEN); printf(" %s\n", pszStr); SetConsoleColor(FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE); LeaveCriticalSection(&g_cs);}//写者线程函数unsigned int __stdcall WriterThreadFun(PVOID pM){ WriterPrintf("写者线程进入等待中..."); //等待读文件的读者为0 AcquireSRWLockExclusive(&g_srwLock); //写文件 WriterPrintf(" 写者开始写文件..."); Sleep(rand()%100); WriterPrintf(" 写者结束写文件"); //标记写文件结束 ReleaseSRWLockExclusive(&g_srwLock); return 0;}int main(){ //初始化事件和关键段 InitializeCriticalSection(&g_cs); InitializeSRWLock(&g_srwLock); int i; HANDLE hThread[READER_NUM + 1]; //先启动两个读者线程 for(i = 1; i <= 2; i++) hThread[i] = (HANDLE)_beginthreadex(NULL, 0, ReaderThreadFun , NULL, 0, NULL); //启动写者线程 hThread[0] = (HANDLE)_beginthreadex(NULL, 0, WriterThreadFun, NULL, 0, NULL); Sleep(50); //最后启动其它读者结程 for ( ; i <= READER_NUM; i++) hThread[i] = (HANDLE)_beginthreadex(NULL, 0, ReaderThreadFun, NULL, 0, NULL); WaitForMultipleObjects(READER_NUM + 1, hThread, TRUE, INFINITE); for(i = 0; i < READER_NUM + 1; i++) CloseHandle(hThread[i]); //销毁 DeleteCriticalSection(&g_cs); return 0; }

加成两个写者,验证结果也正确。

 

最后总结一下读写锁SRWLock

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

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

转载地址:http://jenel.baihongyu.com/

你可能感兴趣的文章
使用阿里云容器监控服务与第三方监控框架集成搭建自己的容器看板
查看>>
PHP time zone unknown Fail
查看>>
[UML]UML系列——用例图中的各种关系(include、extend)
查看>>
oracle v$sysstat性能视图
查看>>
聊Code review(上)
查看>>
ORA-02374 ORA-12899 ORA-02372
查看>>
[MySQL Bug]DDL操作导致备库复制中断
查看>>
Spring Boot——2分钟构建spring web mvc REST风格HelloWorld
查看>>
什么是可重入函数
查看>>
如何防止远程程序与RDS PG连接中断
查看>>
进程间通信之-信号signal--linux内核剖析(九)
查看>>
oracle 10g for linux
查看>>
认识一下Android 事件分发机制
查看>>
Servlet的API(一)
查看>>
网络01:双无线路由器无缝对接设置
查看>>
实现Android和PC之间的蓝牙通信
查看>>
rails将类常量重构到数据库对应的表中之二
查看>>
微软面试题:写程序找出二叉树的深度
查看>>
[Google Guava] 1.2-前置条件
查看>>
OEA框架 2.9 Pre-Alpha 源码公布
查看>>