本文配套程式為: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 控制台顏色設定》。
《多線程十大經典案例之一雙線程讀寫隊列資料》完整代碼:
//秒殺多線程第十六篇 多線程十大經典案例之一 雙線程讀寫隊列資料//http://blog.csdn.net/MoreWindows/article/details/8646902#include <stdio.h>#include <process.h>#include <windows.h>#include <time.h>const int QUEUE_LEN = 5;int g_arrDataQueue[QUEUE_LEN];int g_i, g_j, g_nDataNum;//關鍵段 用於保證互斥的在螢幕上輸出CRITICAL_SECTION g_cs;//訊號量 g_hEmpty表示隊列中空位 g_hFull表示隊列中非空位HANDLE g_hEmpty, g_hFull;//設定控制台輸出顏色BOOL SetConsoleColor(WORD wAttributes){HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);if (hConsole == INVALID_HANDLE_VALUE)return FALSE;return SetConsoleTextAttribute(hConsole, wAttributes);}//讀資料線程函數unsigned int __stdcall ReaderThreadFun(PVOID pM){int nData = 0;while (nData < 20){WaitForSingleObject(g_hFull, INFINITE);nData = g_arrDataQueue[g_i];g_i = (g_i + 1) % QUEUE_LEN;EnterCriticalSection(&g_cs);printf("從隊列中讀資料%d\n", nData);LeaveCriticalSection(&g_cs);Sleep(rand() % 300);ReleaseSemaphore(g_hEmpty, 1, NULL);}return 0;}//寫資料線程函數unsigned int __stdcall WriterThreadFun(PVOID pM){int nData = 0;while (nData < 20){WaitForSingleObject(g_hEmpty, INFINITE);g_arrDataQueue[g_j] = ++nData;g_j = (g_j + 1) % QUEUE_LEN;EnterCriticalSection(&g_cs);SetConsoleColor(FOREGROUND_GREEN);printf(" 將資料%d寫入隊列\n", nData);SetConsoleColor(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);LeaveCriticalSection(&g_cs);Sleep(rand() % 300);ReleaseSemaphore(g_hFull, 1, NULL);}return 0;}int main(){printf(" 秒殺多線程第十六篇 多線程十大經典案例 雙線程讀寫隊列資料\n");printf(" - by MoreWindows( http://blog.csdn.net/MoreWindows/article/details/8646902 ) -\n\n");InitializeCriticalSection(&g_cs);g_hEmpty = CreateSemaphore(NULL, QUEUE_LEN, QUEUE_LEN, NULL);g_hFull = CreateSemaphore(NULL, 0, QUEUE_LEN, NULL);srand(time(NULL));g_i = g_j = 0;HANDLE hThread[2];hThread[0] = (HANDLE)_beginthreadex(NULL, 0, ReaderThreadFun, NULL, 0, NULL);hThread[1] = (HANDLE)_beginthreadex(NULL, 0, WriterThreadFun, NULL, 0, NULL);WaitForMultipleObjects(2, hThread, TRUE, INFINITE);for (int i = 0; i < 2; i++)CloseHandle(hThread[i]);CloseHandle(g_hEmpty);CloseHandle(g_hFull);DeleteCriticalSection(&g_cs);return 0;}
《多線程十大經典案例之一雙線程讀寫隊列資料》運行結果:
程式運行結果如下:
本文配套程式為:http://download.csdn.net/detail/morewindows/5136035
轉載請標明出處,原文地址:http://blog.csdn.net/morewindows/article/details/8646902
歡迎關注微博:http://weibo.com/MoreWindows