【文起】亲爱的,谢谢你最近一直在关注租房信息。辛苦了宝贝儿,豆豆只能多看书来回报宝宝,爱你
第九章 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>
【文尾】如果文章对您有帮助,请留下对我和蟹儿的祝福。如果需要源代码,请留下祝福以及您邮箱,我会在第一时间回复,包含此程序中的疑问,欢迎一起讨论