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

    这类博弈只需要记住一点,一个由多个游戏组成的游戏sg值为这多个游戏的sg值异或和. 也就是所有对一整个nim游戏它的sg值即为每一小堆的sg的异或和. hdu 5795 这题就是可以选择把一堆石子分成 ...

  2. 利用php的序列化和反序列化来做简单的数据本地存储

    利用php的序列化和反序列化来做简单的数据本地存储 如下程序可以做为一个工具类 /** * 利用php的序列化和反序列化来做简单的数据本地存储 */ class objectdb { private ...

  3. ios CoreBluetooth 警告 is being dealloc'ed while pending connection

    ios CoreBluetooth 警告 is being dealloc'ed while pending connection CoreBluetooth[WARNING] <CBPerip ...

  4. css读书笔记2:css工作原理

    css就是一种先选择html元素,然后设定选中元素css属性的机制.css选择符合要应用的样式构成一条css规则. 为文档添加样式的3种方法: 1.行内样式,直接写在特定标签的style属性中:2.嵌 ...

  5. 20145218 《Java程序设计》第7周学习总结

    20145218 <Java程序设计>第7周学习总结 教材学习内容总结 第十二章 Lambda 如果使用JDK8的话,可以使用Lambda特性去除重复的信息. 在只有Lambda表达式的情 ...

  6. js键盘操作事件

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  7. [svn] 分支开发

    参考博客: http://www.cnblogs.com/cxd4321/archive/2012/07/12/2588110.html (1)为什么要使用SVN分支开发和主干合并? 目的:在SVN下 ...

  8. java之如何实现调用启动一个可执行文件,exe

    /* * 运行可执行文件:.exe * 当要执行一个本地机器上的可执行文件时, * 可以使用java.lang包中的Runtime类,首先使用Runtime类,首先 * 使用Runtime类声明一个对 ...

  9. 张艾迪(创始人):发明整个世界+224C个国家

    Eidyzhang:发明整个世界+224C个国家 Eidyzhang: Genius.Founder.CEO.23 I 世界级最高级创始人.世界最高级FounderCEO 出生在亚洲中国.Eidyzh ...

  10. js 数组 转

    1.数组的创建 var arrayObj = new Array(); //创建一个数组 var arrayObj = new Array([size]); //创建一个数组并指定长度,注意不是上限, ...