【文起】親愛的,謝謝你最近一直在關注租房信息。辛苦了寶貝兒,豆豆只能多看書來回報寶寶,愛你
第九章 Queue程序筆記
程序運行情況:
1、Queue程序的目的是熟悉兩個知識點
a)互斥對象內核對象,包含共享資源
b)信標對象,標記當前可以使用的資源數。
2、我們創建了一個結構體
//每次寫入共享資源池中的值爲:1、第幾個線程;2、該線程的第幾次請求
struct ELENMENT
{
DWORD dwProcessNum;//第幾個線程
DWORD dwProcessRequestNum;//該線程的第幾次請求
};
typedef ELENMENT* PELENMENT;
3、再創建一個class,用來模擬服務器與客戶端之間的資源池
class CQueueList
{
public:
CQueueList(int nMaxNum);
~CQueueList();
//模擬客戶端請求消息,給共享池添加數據
BOOL AppendList(PELENMENT pElenment,DWORD dwTimeout);
//模擬服務器處理請求消息,從共享池中讀出數據並移除之
BOOL RemoveList(PELENMENT pElenment,DWORD dwTimeOut);
private:
PELENMENT m_pElenments;
int m_nMaxNum;//共享池最大可存多少請求
HANDLE m_h[2];
HANDLE &m_hMutex;//互斥內核對象
HANDLE &m_hSemaphore;//信標兩個作用:1、共享池中是否有數據;2、共享池是否滿了
};
4、如下是CQueueList類的成員函數:
//初始化
CQueueList::CQueueList(int nMaxNum)
:m_hMutex(m_h[0]),m_hSemaphore(m_h[1])
{
m_nMaxNum = nMaxNum;
m_pElenments = (PELENMENT)HeapAlloc(GetProcessHeap(),0,sizeof(ELENMENT) * nMaxNum);
m_hMutex = CreateMutex(NULL,FALSE,NULL);
m_hSemaphore = CreateSemaphore(NULL,0,nMaxNum,NULL);
}
CQueueList::~CQueueList()
{
CloseHandle(m_hMutex);
CloseHandle(m_hSemaphore);
HeapFree(GetProcessHeap(),0,m_pElenments);
}
//模擬客戶端
BOOL CQueueList::AppendList(PELENMENT pElenment, DWORD dwTimeout)
{
BOOL bOk = FALSE;
//共享池是否沒其他線程使用
DWORD dwType = WaitForSingleObject(m_hMutex,dwTimeout);
if (WAIT_OBJECT_0 == dwType)
{
//可以使用該對象了,通過信標看看資源池是否滿,順便把上次資源池有多少線程也讀出來
LONG lPreCount;
bOk = ReleaseSemaphore(m_hSemaphore,1,&lPreCount);
if (bOk)
{
//可以新增
m_pElenments[lPreCount] = *pElenment;
}
else
{
//共享池滿了
SetLastError(ERROR_DATABASE_FULL);
}
//操作結束了,釋放互斥內核對象
ReleaseMutex(m_hMutex);
}
else
{
SetLastError(ERROR_TIMEOUT);
}
return bOk;
}
//模仿服務器
BOOL CQueueList::RemoveList(PELENMENT pElenment, DWORD dwTimeOut)
{
//必須滿足兩個條件才能觸發服務器線程:1、共享池沒有其他線程使用;2、共享池有數據
BOOL bOk = (WAIT_OBJECT_0 == WaitForMultipleObjects(2,m_h,TRUE,dwTimeOut));
if (bOk)
{
//讀數據且後面的往前移
*pElenment = m_pElenments[0];
MoveMemory(&m_pElenments[0],&m_pElenments[1],sizeof(ELENMENT) * (m_nMaxNum - 1));
//操作好了,釋放互斥對象,信標在Wait....函數中已經減一了
ReleaseMutex(m_hMutex);
}
else
{
SetLastError(ERROR_TIMEOUT);
}
return bOk;
}
全局變量:
CQueueList g_QueueList(10);//共享池大小爲10
BOOL g_fShutDown = FALSE;
HANDLE g_hThreads[MAXIMUM_WAIT_OBJECTS];
int g_nThreadNums = 0;
啓動線程:
DWORD dwThread;
//啓動4個客戶端線程
for (int i = 1; i < 5;i++)
{
g_hThreads[g_nThreadNums++] =
CreateThread(NULL,0,ClientThread,(LPVOID)(INT_PTR)i,0,&dwThread);
}
//啓動2個服務器線程
for (int i = 1; i < 3;i++)
{
g_hThreads[g_nThreadNums++] =
CreateThread(NULL,0,ServerThread,(LPVOID)(INT_PTR)i,0,&dwThread);
}
DWORD WINAPI ClientThread(LPVOID pvParam)
{
ULONG ulClientNum = PtrToLong(pvParam);
HWND hwnd = FindWindow(NULL,_T("Queue"));
hwnd = GetDlgItem(hwnd,IDC_LIST_CLIENT);
for (int nRequest = 1;!g_fShutDown;nRequest++)
{
TCHAR sz[1024] = {0};
ELENMENT e ={ulClientNum,nRequest};//存儲第幾個線程、第幾次請求
if (g_QueueList.AppendList(&e,200))
{
//寫進入了
wsprintf(sz,_T("Client %d Sending ResquestTime:%d"),ulClientNum,nRequest);
}
else
{
//沒寫進去,看看是超時還是滿了
wsprintf(sz,_T("Client %d Sending ResquestTime:%d %s"),ulClientNum,nRequest,
(ERROR_TIMEOUT == GetLastError())?_T("timeout"):_T("Full"));
}
ListBox_SetCurSel(hwnd,ListBox_AddString(hwnd,sz));
Sleep(2500);//休息下
}
return 0;
}
DWORD WINAPI ServerThread(PVOID pvParam)
{
ULONG ulServerNum = PtrToLong(pvParam);
HWND hwnd = FindWindow(NULL,_T("Queue"));
hwnd = GetDlgItem(hwnd,IDC_LIST_SERVER);
if (1 == ulServerNum )
{
ListBox_SetCurSel(hwnd,ListBox_AddString(hwnd,_T("服務器豆漿已經啓動......")));
}
else
{
ListBox_SetCurSel(hwnd,ListBox_AddString(hwnd,_T("服務器蟹蟹已經啓動......")));
}
while (!g_fShutDown)
{
TCHAR sz[1024] = {0};
ELENMENT e;
if (g_QueueList.RemoveList(&e,5000))
{
//有數據了,讀出來
wsprintf(sz,_T("Server:%d Done Client %d RequestTime %d"),ulServerNum,
e.dwProcessNum,e.dwProcessRequestNum);
Sleep(2000 * e.dwProcessNum);//需要時間去處理客戶端請求
}
else
{
wsprintf(sz,_T("Server:%d TimeOut"),ulServerNum);
}
ListBox_SetCurSel(hwnd,ListBox_AddString(hwnd,sz));
}
return 0;
}
7、退出窗口時,需要把申請的這些線程都Close掉,調用WM_DESTORY消息的處理函數
void CQueueDlg::OnDestroy()
{
while (g_nThreadNums--)
{
CloseHandle(g_hThreads[g_nThreadNums]);
}
CDialog::OnDestroy();
// TODO: 在此處添加消息處理程序代碼
}
如此,這個程序巧妙的運用了互斥對象內核對象以及信標對象。
需要添加的頭文件是:
#include <WindowsX.h>
#include <process.h>
【文尾】如果文章對您有幫助,請留下對我和蟹兒的祝福。如果需要源代碼,請留下祝福以及您郵箱,我會在第一時間回覆,包含此程序中的疑問,歡迎一起討論