在《秒杀多线程第十一篇读者写者问题》文章中我们使用事件和一个记录读者个数的变量来解决读者写者问题。问题虽然得到了解决,但代码有点复杂。本篇将介绍一种新方法——读写锁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. #include<stdio.h>
    #include<process.h>
    #include<Windows.h>
    /*按照逻辑,即使是读文件线程先运行,也要一直阻塞到第一个写线程执行完(因为写线程不运行,就没有数据。此时,读线程的执行就没有意义)。*/

    //设置控制台颜色输出
    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");
    //读者申请读取文件
    AcquireSRWLockShared(&g_srwLock);

    //读取文件
    ReaderPrintf("编号为%d的读者开始读取文件...\n");
    Sleep(rand() % 100);
    ReaderPrintf("编号为%d的读者结束读取文件!\n");

    ReleaseSRWLockShared(&g_srwLock);
    return 0;
    }

    void WriterPrintf(char *pszStr)
    {
    EnterCriticalSection(&g_cs);
    SetConsoleColor(FOREGROUND_GREEN);
    printf(" %s\n", pszStr);
    SetConsoleColor(FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED);
    LeaveCriticalSection(&g_cs);
    }
    //写者函数
    unsigned int _stdcall WriterThreadFun(PVOID pM)
    {
    WriterPrintf("写者等待写文件...\n");
    //写者申请写文件
    AcquireSRWLockExclusive(&g_srwLock);

    WriterPrintf("写者正在写文件...\n");

    Sleep(rand() % 100);

    WriterPrintf("写者写文件完成!\n");

    ReleaseSRWLockExclusive(&g_srwLock);

    return 0;
    }

    int main()
    {
    printf("读者写者问题续 读写锁SRWLock\n");
    printf(" -- by MoreWindows( http://blog.csdn.net/MoreWindows ) --\n\n");

    InitializeCriticalSection(&g_cs);
    InitializeSRWLock(&g_srwLock);

    HANDLE hThread[READER_NUM + 1];
    int i;
    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);
    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);

    system("pause");
    return 0;
    }

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

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

最后总结一下读写锁SRWLock

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

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

转载请标明出处,原文地址:http://blog.csdn.net/morewindows/article/details/7650574

如果觉得本文对您有帮助,请点击‘顶’支持一下,您的支持是我写作最大的动力,谢谢。

读者写者问题继 读写锁SRWLock的更多相关文章

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

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

  2. 转---秒杀多线程第十四篇 读者写者问题继 读写锁SRWLock

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

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

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

  4. 多线程 读写锁SRWLock

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

  5. 读写锁 SRWLOCK

    读写锁在对资源进行保护的同时,还能区分想要读取资源值的线程(读取者线程)和想要更新资源的线程(写入者线程). 对于读取者线程,读写锁会允许他们并发的执行.当有写入者线程在占有资源时,读写锁会让其它写入 ...

  6. 最新Windows下c++读写锁SRWLock介绍

    https://blog.csdn.net/MoreWindows/article/details/7650574 https://blog.csdn.net/chenzhjlf/article/de ...

  7. 读者写者问题(有bug 后续更改)

    与上一篇<秒杀多线程第十篇 生产者消费者问题>的生产者消费者问题一样,读者写者也是一个非常著名的同步问题.读者写者问题描述非常简单,有一个写者很多读者,多个读者可以同时读文件,但写者在写文 ...

  8. sqlite3 读写锁

    转载:https://blog.csdn.net/u012218838/article/details/79362929(sqlite3 使用读写锁SRWLOCK例子) 转载:https://my.o ...

  9. Linux多线程实践(6) --Posix读写锁解决读者写者问题

    Posix读写锁 int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *rest ...

随机推荐

  1. mybatis动态SQL中的sql片段

    在mybatis中通过使用SQL片段可以提高代码的重用性,如下情景: 1.创建动态SQL <sql id="sql_count">select count(*)< ...

  2. LinuxShell脚本攻略--第六章 B计划

    tar -A或--catenate:新增文件到以存在的备份文件: -B:设置区块大小: -c或--create:建立新的备份文件: -C <目录>:这个选项用在解压缩,若要在特定目录解压缩 ...

  3. ios开发者证书 签发者无效

    2月14日以后,由于苹果更新安全证书:会导致本机制作的所有开发者证书无效: 钥匙串里的开发者证书无法使用 解决方式: 重新下载苹果公司的安全证书,并安装 1: 先在钥匙串里搜索到老的证书,如果有,请先 ...

  4. Question store (Repeated review)

    题目36 - ACM在线评测系统http://acm.nyist.net/JudgeOnline/problem.php?pid=36 用户名密码INVATION  讲道理太卡 第一:要注意不同的函数 ...

  5. 安装 request模块

    python3 requests 安装包下载安装[windows] 听语音 | 浏览:54 | 更新:2016-07-25 17:09 windows下直接使用:easy_install reques ...

  6. jquery上传插件Jquery.uploadify.js-转

    Uploadify是JQuery的一个上传插件,实现的效果非常不错,带进度显示.不过官方提供的实例时php版本的,本文将详细介绍Uploadify在Aspnet中的使用,您也可以点击下面的链接进行演示 ...

  7. uva 1631

    1631 Locker A password locker with N digits, each digit can be rotated to 0-9 circularly. You can ro ...

  8. Card Collector(HDU 4336)

    Card Collector Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)To ...

  9. BZOJ4003 [JLOI2015]城池攻占

    这题有两种做法来着... 第一种就是一开始想到的比较不靠谱,不过貌似可以过掉: 看从$1$号节点开始到$p$号节点最大需要的体力,记录单调上升的体力,询问的时候二分跳着走就可以了 不过精度问题还有可能 ...

  10. iOS App Icon图标 尺寸规范

    Commit to AppStore:1024*1024 //for App IconIcon-60@3x.png:180*180 //iPhone 6 Plus (@3x)Icon-60@2x.pn ...