您的位置:首页 > 产品设计 > UI/UE

Windows核心编程<读书笔记九>手把手写Queue程序

2011-12-06 23:09 696 查看
【文起】亲爱的,谢谢你最近一直在关注租房信息。辛苦了宝贝儿,豆豆只能多看书来回报宝宝,爱你

第九章 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;
}


5、在对话框初始函数中,申请4个客户端线程,2个服务器线程,为了方便统计,我们定义了一些全局变量:
全局变量:

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);
}


6、服务器和客户端线程函数:

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>


【文尾】如果文章对您有帮助,请留下对我和蟹儿的祝福。如果需要源代码,请留下祝福以及您邮箱,我会在第一时间回复,包含此程序中的疑问,欢迎一起讨论
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: