14.[個人]C++線程入門到進階(14)----雙線程讀寫隊列數據

本文配套程序下載地址爲:http://download.csdn.net/detail/morewindows/5136035

轉載請標明出處,原文地址:http://blog.csdn.net/morewindows/article/details/8646902

歡迎關注微博:http://weibo.com/MoreWindows

 

在《秒殺多線程系列》的前十五篇中介紹多線程的相關概念,多線程同步互斥問題《秒殺多線程第四篇一個經典的多線程同步問題》及解決多線程同步互斥的常用方法——關鍵段事件互斥量信號量讀寫鎖。爲了讓大家更加熟練運用多線程,將會有十篇文章來講解十個多線程使用案例,相信看完這十篇後會讓你能更加遊刃有餘的使用多線程。

首先來看第一篇——《秒殺多線程第十六篇 多線程十大經典案例之一 雙線程讀寫隊列數據》

《多線程十大經典案例之一雙線程讀寫隊列數據》案例描述:

MFC對話框中一個按鈕的響應函數實現兩個功能:
顯示數據同時處理數據,因此開兩個線程,一個線程顯示數據(開了一個定時器,響應WM_TIMER消息按照一定時間間隔向TeeChart圖表添加數據並顯示)同時在隊列隊尾添加數據,另一個線程從該隊列隊頭去數據來處理。

本案例來源於http://bbs.csdn.net/topics/390383114,感謝hehening88提供題目,特此鳴謝。

下面就來解決這個案例。先來分析下。

 

《多線程十大經典案例之一雙線程讀寫隊列數據》案例分析:

這個案例是一個線程向隊列中的隊列頭部讀取數據,一個線程向隊列中的隊列尾部寫入數據。看起來很像讀者寫者問題(見《秒殺多線程第十一篇讀者寫者問題》和《秒殺多線程第十四篇讀者寫者問題繼讀寫鎖SRWLock》),但其實不然,如果將隊列看成緩衝區,這個案例明顯是個生產者消費者問題(見《秒殺多線程第十篇生產者消費者問題》)。因此我們仿照生產者消費者的思路來具體分析下案例中的“等待”情況:

    1.     當隊列爲空時,讀取數據線程必須等待寫入數據向隊列中寫入數據。也就是說當隊列爲空時,讀取數據線程要等待隊列中有數據

    2.     當隊列滿時,寫入數據線程必須等待讀取數據線程向隊列中讀取數據。也就是說當隊列滿時,寫入數據線程要等待隊列中有空位

訪問隊列時,需要互斥嗎?這將依賴於隊列的數據結構實現,如果使用STL中的vector,由於vector會動態增長。因此要做互斥保護。如果使用循環隊列,那麼讀取數據線程擁有讀取指針,寫入數據線程擁有寫入指針,各自將訪問隊列中不同位置上的數據,因此不用進行互斥保護。

分析完畢後,再來考慮使用什麼樣的數據結構,同樣依照《秒殺多線程第十篇生產者消費者問題》中的做法。使用兩個信號量,一個來記錄循環隊列中空位的個數,一個來記錄循環隊列中產品的個數(非空位個數)。代碼非常容易寫出,下面給出完整的源代碼。

代碼中的信號量相關函數可以參考《秒殺多線程第八篇經典線程同步信號量Semaphore》,代碼中的SetConsoleColor是用來改變控制檯的文字顏色,具體可以參考《VC 控制檯顏色設置》。

 

《多線程十大經典案例之一雙線程讀寫隊列數據》完整代碼:

[cpp] view plain copy
  1. //秒殺多線程第十六篇 多線程十大經典案例之一 雙線程讀寫隊列數據  
  2. //http://blog.csdn.net/MoreWindows/article/details/8646902  
  3. #include <stdio.h>  
  4. #include <process.h>  
  5. #include <windows.h>  
  6. #include <time.h>  
  7. const int QUEUE_LEN = 5;  
  8. int g_arrDataQueue[QUEUE_LEN];  
  9. int g_i, g_j, g_nDataNum;  
  10. //關鍵段 用於保證互斥的在屏幕上輸出  
  11. CRITICAL_SECTION g_cs;  
  12. //信號量 g_hEmpty表示隊列中空位 g_hFull表示隊列中非空位  
  13. HANDLE     g_hEmpty, g_hFull;  
  14. //設置控制檯輸出顏色  
  15. BOOL SetConsoleColor(WORD wAttributes)  
  16. {  
  17.     HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);  
  18.     if (hConsole == INVALID_HANDLE_VALUE)  
  19.         return FALSE;     
  20.     return SetConsoleTextAttribute(hConsole, wAttributes);  
  21. }  
  22. //讀數據線程函數  
  23. unsigned int __stdcall ReaderThreadFun(PVOID pM)  
  24. {  
  25.     int nData = 0;  
  26.     while (nData < 20)  
  27.     {  
  28.         WaitForSingleObject(g_hFull, INFINITE);  
  29.         nData = g_arrDataQueue[g_i];  
  30.         g_i = (g_i + 1) % QUEUE_LEN;  
  31.         EnterCriticalSection(&g_cs);  
  32.         printf("從隊列中讀數據%d\n", nData);  
  33.         LeaveCriticalSection(&g_cs);  
  34.         Sleep(rand() % 300);  
  35.         ReleaseSemaphore(g_hEmpty, 1, NULL);  
  36.     }  
  37.     return 0;  
  38. }  
  39. //寫數據線程函數  
  40. unsigned int __stdcall WriterThreadFun(PVOID pM)  
  41. {  
  42.     int nData = 0;  
  43.     while (nData < 20)  
  44.     {  
  45.         WaitForSingleObject(g_hEmpty, INFINITE);  
  46.         g_arrDataQueue[g_j] = ++nData;  
  47.         g_j = (g_j + 1) % QUEUE_LEN;  
  48.         EnterCriticalSection(&g_cs);  
  49.         SetConsoleColor(FOREGROUND_GREEN);  
  50.         printf("    將數據%d寫入隊列\n", nData);  
  51.         SetConsoleColor(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);  
  52.         LeaveCriticalSection(&g_cs);  
  53.         Sleep(rand() % 300);  
  54.         ReleaseSemaphore(g_hFull, 1, NULL);  
  55.     }  
  56.     return 0;  
  57. }  
  58. int main()  
  59. {  
  60.     printf("     秒殺多線程第十六篇 多線程十大經典案例 雙線程讀寫隊列數據\n");  
  61.     printf(" - by MoreWindows( http://blog.csdn.net/MoreWindows/article/details/8646902 ) -\n\n");  
  62.       
  63.     InitializeCriticalSection(&g_cs);  
  64.     g_hEmpty = CreateSemaphore(NULL, QUEUE_LEN, QUEUE_LEN, NULL);  
  65.     g_hFull = CreateSemaphore(NULL, 0, QUEUE_LEN, NULL);  
  66.       
  67.     srand(time(NULL));  
  68.     g_i = g_j = 0;  
  69.     HANDLE hThread[2];  
  70.     hThread[0] = (HANDLE)_beginthreadex(NULL, 0, ReaderThreadFun, NULL, 0, NULL);  
  71.     hThread[1] = (HANDLE)_beginthreadex(NULL, 0, WriterThreadFun, NULL, 0, NULL);  
  72.       
  73.     WaitForMultipleObjects(2, hThread, TRUE, INFINITE);  
  74.       
  75.     for (int i = 0; i < 2; i++)  
  76.         CloseHandle(hThread[i]);  
  77.     CloseHandle(g_hEmpty);  
  78.     CloseHandle(g_hFull);  
  79.     DeleteCriticalSection(&g_cs);  
  80.     return 0;  
  81. }  

 

《多線程十大經典案例之一雙線程讀寫隊列數據》運行結果:

程序運行結果如下:

本文配套程序下載地址爲:http://download.csdn.net/detail/morewindows/5136035

轉載請標明出處,原文地址:http://blog.csdn.net/morewindows/article/details/8646902

歡迎關注微博:http://weibo.com/MoreWindows

發佈了51 篇原創文章 · 獲贊 149 · 訪問量 31萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章