日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

秒杀多线程第十一篇 读者写者问题

發布時間:2024/4/11 编程问答 52 豆豆
生活随笔 收集整理的這篇文章主要介紹了 秒杀多线程第十一篇 读者写者问题 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

與上一篇《秒殺多線程第十篇 生產者消費者問題》的生產者消費者問題一樣,讀者寫者也是一個非常著名的同步問題。讀者寫者問題描述非常簡單,有一個寫者很多讀者,多個讀者可以同時讀文件,但寫者在寫文件時不允許有讀者在讀文件,同樣有讀者在讀文件時寫者也不去能寫文件。

上面是讀者寫者問題示意圖,類似于生產者消費者問題的分析過程,首先來找找哪些是屬于“等待”情況。

第一.寫者要等到沒有讀者時才能去寫文件。

第二.所有讀者要等待寫者完成寫文件后才能去讀文件。

找完“等待”情況后,再看看有沒有要互斥訪問的資源。由于只有一個寫者而讀者們是可以共享的讀文件,所以按題目要求并沒有需要互斥訪問的資源。類似于上一篇中美觀的彩色輸出,我們對生產者輸出代碼進行了顏色設置(在控制臺輸出顏色設置參見《VC 控制臺顏色設置》)。因此在這里要加個互斥訪問,不然很有可能在寫者線程將控制臺顏色設置還原之前,讀者線程就已經有輸出了。所以要對輸出語句作個互斥訪問處理,修改后的讀者及寫者的輸出函數如下所示:

[cpp]?view plaincopy
  • //讀者線程輸出函數??
  • void?ReaderPrintf(char?*pszFormat,?...)??
  • {??
  • ????va_list???pArgList;??
  • ????va_start(pArgList,?pszFormat);??
  • ????EnterCriticalSection(&g_cs);??
  • ????vfprintf(stdout,?pszFormat,?pArgList);??
  • ????LeaveCriticalSection(&g_cs);??
  • ????va_end(pArgList);??
  • }??
  • //寫者線程輸出函數??
  • void?WriterPrintf(char?*pszStr)??
  • {??
  • ????EnterCriticalSection(&g_cs);??
  • ????SetConsoleColor(FOREGROUND_GREEN);??
  • ????printf("?????%s\n",?pszStr);??
  • ????SetConsoleColor(FOREGROUND_RED?|?FOREGROUND_GREEN?|?FOREGROUND_BLUE);??
  • ????LeaveCriticalSection(&g_cs);??
  • }??
  • 讀者線程輸出函數所使用的可變參數詳見《C,C++中使用可變參數》。

    ???????解決了互斥輸出問題,接下來再考慮如何實現同步問題。可以設置一個變量來記錄正在讀文件的讀者個數,第一個開始讀文件的讀者要負責將關閉允許寫者進入的標志,最后一個結束讀文件的讀者要負責打開允許寫者進入的標志。這樣第一種“等待”情況就解決了。第二種“等待”情況是有寫者進入時所以讀者不能進入,使用一個事件就可以完成這個任務了——所有讀者都要等待這個事件而寫者負責觸發事件和設置事件為未觸發。詳細見代碼中注釋:

    [cpp]?view plaincopy
  • //讀者與寫者問題??
  • #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,?g_cs_writer_count;??
  • HANDLE?g_hEventWriter,?g_hEventNoReader;??
  • int?g_nReaderCount;??
  • //讀者線程輸出函數(變參函數的實現)??
  • 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());??
  • ????//等待寫者完成??
  • ????WaitForSingleObject(g_hEventWriter,?INFINITE);??
  • ??
  • ????//讀者個數增加??
  • ????EnterCriticalSection(&g_cs_writer_count);??
  • ????g_nReaderCount++;??
  • ????if?(g_nReaderCount?==?1)??
  • ????????ResetEvent(g_hEventNoReader);??
  • ????LeaveCriticalSection(&g_cs_writer_count);??
  • ??
  • ????//讀取文件??
  • ????ReaderPrintf("編號為%d的讀者開始讀取文件...\n",?GetCurrentThreadId());??
  • ??
  • ????Sleep(rand()?%?100);??
  • ??
  • ????//結束閱讀,讀者個數減小,空位增加??
  • ????ReaderPrintf("?編號為%d的讀者結束讀取文件\n",?GetCurrentThreadId());??
  • ??
  • ????//讀者個數減少??
  • ????EnterCriticalSection(&g_cs_writer_count);??
  • ????g_nReaderCount--;??
  • ????if?(g_nReaderCount?==?0)??
  • ????????SetEvent(g_hEventNoReader);??
  • ????LeaveCriticalSection(&g_cs_writer_count);??
  • ??
  • ????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("寫者線程進入等待中...");??
  • ????//等待讀文件的讀者為零??
  • ????WaitForSingleObject(g_hEventNoReader,?INFINITE);??
  • ????//標記寫者正在寫文件??
  • ????ResetEvent(g_hEventWriter);??
  • ??????????
  • ????//寫文件??
  • ????WriterPrintf("??寫者開始寫文件.....");??
  • ????Sleep(rand()?%?100);??
  • ????WriterPrintf("??寫者結束寫文件");??
  • ??
  • ????//標記寫者結束寫文件??
  • ????SetEvent(g_hEventWriter);??
  • ????return?0;??
  • }??
  • int?main()??
  • {??
  • ????printf("??讀者寫者問題\n");??
  • ????printf("?--?by?MoreWindows(?http://blog.csdn.net/MoreWindows?)?--\n\n");??
  • ??
  • ????//初始化事件和信號量??
  • ????InitializeCriticalSection(&g_cs);??
  • ????InitializeCriticalSection(&g_cs_writer_count);??
  • ??
  • ????//手動置位,初始已觸發??
  • ????g_hEventWriter?=?CreateEvent(NULL,?TRUE,?TRUE,?NULL);??
  • ????g_hEventNoReader??=?CreateEvent(NULL,?FALSE,?TRUE,?NULL);??
  • ????g_nReaderCount?=?0;??
  • ??
  • ????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]);??
  • ??
  • ????//銷毀事件和信號量??
  • ????CloseHandle(g_hEventWriter);??
  • ????CloseHandle(g_hEventNoReader);??
  • ????DeleteCriticalSection(&g_cs);??
  • ????DeleteCriticalSection(&g_cs_writer_count);??
  • ????return?0;??
  • }??
  • 運行結果如下所示:

    根據結果可以看出當有讀者在讀文件時,寫者線程會進入等待狀態中。當寫者線程在寫文件時,讀者線程也會排隊等待,說明讀者和寫者已經完成了同步。

    ?

    本系列通過經典線程同步問題來列舉線程同步手段的關鍵段事件互斥量信號量,并作對這四種方法進行了總結。然后又通過二個著名的線程同步實例——生產者消費者問題和讀者寫者問題來強化對多線程同步互斥的理解與運用。希望讀者們能夠熟練掌握,從而在筆試面試中能夠順利的“秒殺”多線程的相關試題,獲得自己滿意的offer

    ?

    從《秒殺多線程第十篇生產者消費者問題》到《秒殺多線程第十一篇讀者寫者問題》可以得出多線程問題的關鍵在于找到所有“等待”情況和判斷有無需要互斥訪問的資源。那么如何從實際問題中更好更快更全面的找出這些了?請看《秒殺多線程第十二篇多線程同步內功心法——PV操作上》和《秒殺多線程第十三篇多線程同步內功心法——PV操作下》這二篇以加強解決多線程同步問題的“內功”。??

    ?

    另外,讀者寫者問題可以用讀寫鎖SRWLock來解決,請看《秒殺多線程第十四篇 讀者寫者問題繼 讀寫鎖SRWLock

    總結

    以上是生活随笔為你收集整理的秒杀多线程第十一篇 读者写者问题的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。