Windows核心编程<读书笔记九>手把手写Queue程序
2011-12-06 23:09
696 查看
【文起】亲爱的,谢谢你最近一直在关注租房信息。辛苦了宝贝儿,豆豆只能多看书来回报宝宝,爱你
第九章 Queue程序笔记
程序运行情况:
![](http://hi.csdn.net/attachment/201112/6/0_13231843256Dat.gif)
1、Queue程序的目的是熟悉两个知识点
a)互斥对象内核对象,包含共享资源
b)信标对象,标记当前可以使用的资源数。
2、我们创建了一个结构体
3、再创建一个class,用来模拟服务器与客户端之间的资源池
4、如下是CQueueList类的成员函数:
5、在对话框初始函数中,申请4个客户端线程,2个服务器线程,为了方便统计,我们定义了一些全局变量:
全局变量:
6、服务器和客户端线程函数:
7、退出窗口时,需要把申请的这些线程都Close掉,调用WM_DESTORY消息的处理函数
如此,这个程序巧妙的运用了互斥对象内核对象以及信标对象。
需要添加的头文件是:
【文尾】如果文章对您有帮助,请留下对我和蟹儿的祝福。如果需要源代码,请留下祝福以及您邮箱,我会在第一时间回复,包含此程序中的疑问,欢迎一起讨论
第九章 Queue程序笔记
程序运行情况:
![](http://hi.csdn.net/attachment/201112/6/0_13231843256Dat.gif)
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>
【文尾】如果文章对您有帮助,请留下对我和蟹儿的祝福。如果需要源代码,请留下祝福以及您邮箱,我会在第一时间回复,包含此程序中的疑问,欢迎一起讨论
相关文章推荐
- Windows核心编程<读书笔记十七>Applnst程序详解
- Windows核心编程<读书笔记九>线程与内核对象的同步
- Windows核心编程<读书笔记四之程序>显示系统中进程、线程、模块详细信息
- Windows核心编程<读书笔记四> 进程的概念
- Windows核心编程<读书笔记五>作业JOB
- Windows核心编程<读书笔记六> 线程
- Windows核心编程<读书笔记十二>纤程
- Windows核心编程<读书笔记八>线程的同步
- Windows核心编程<读书笔记十三>Windows的内存结构
- Windows核心编程<读书笔记二>Unicode和ANSI
- std::stack<T>和std::queue<T>在执行频率比较高的程序中,效率太低
- Windows核心编程<读书笔记七>线程的调度、优先级以及亲缘性 【含有代码】
- Windows核心编程<读书笔记十七> 内存映射文件
- Windows核心编程<读书笔记五>手把手写JobLab程序
- Windows核心编程<读书笔记十六>线程的堆栈
- Windows核心编程<读书笔记四>return exit(0) ExitProcess的不同之处
- windows核心编程<读书笔记一>---重写Onchar函数
- <<深入理解linux内核>>读书笔记 (一): 内存寻址
- <STL介绍>--Queue用法
- <转>VC++实现Vista和Win7系统低权限程序向高权限程序发消息