• 【多线程】学习12


    以下内容来自:http://blog.csdn.net/morewindows/article/details/7650574

      前面我们使用事件和一个记录读者个数的变量来解决读者写者问题。问题虽然得到了解决,但代码有点复杂。本篇将介绍一种新方法——读写锁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 <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的读者进入等待中...
    ", GetCurrentThreadId());
        //等待写者完成
        AcquireSRWLockShared(&g_srwLock);
    
        Sleep(10);
    
        //读取文件
        ReaderPrintf("编号为%d的读者开始读取文件...
    ", GetCurrentThreadId());
        Sleep(rand() % 100);
        //结束阅读,读者个数减少,空位增加
        ReaderPrintf("  编号为%d的读者结束读取文件
    ", GetCurrentThreadId());
    
        ReleaseSRWLockShared(&g_srwLock);
        return 0;
    }
    //写者线程输出函数
    void WriterPrintf(char *pszStr)
    {
        EnterCriticalSection(&g_cs);
        SetConsoleColor(FOREGROUND_GREEN);
        printf("    %s
    ", 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.读取者和写入者分别调用不同的申请函数和释放函数。

  • 相关阅读:
    51,智联,猎聘,boss 15
    ubuntu重命名[桌面]为[desktop]
    13周让你爱上跑步-计划表
    Typecho的安装 --【Typecho01】.md
    ubuntu跑vue报错:#Error from chokidar # Error: ENOSPC: System limit for number of file watchers reached
    Java中多线程编程--synchronized关键字
    Java中几种常见的设计模式--代理设计模式
    Metaspolit下UAC提权以及日志清除
    JVM初探(五):类的实例化
    JVM初探(四):类加载器
  • 原文地址:https://www.cnblogs.com/dplearning/p/4053742.html
Copyright © 2020-2023  润新知