博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Windows核心编程学习九:利用内核对象进行线程同步
阅读量:5135 次
发布时间:2019-06-13

本文共 7236 字,大约阅读时间需要 24 分钟。

注:源码为学习《Windows核心编程》的一些尝试,非原创。若能有助于一二访客,幸甚。

1.程序框架

 

#include "Queue.h"#include 
#include
#include
#include
#include "resource.h"/************************************************************************/#define chHANDLE_DLGMSG(hWnd, message, fn) \ case (message): return (SetDlgMsgResult(hWnd, uMsg, \ HANDLE_##message((hWnd), (wParam), (lParam), (fn))))// This macro function calls the C runtime's _beginthreadex function. // The C runtime library doesn't want to have any reliance on Windows' data // types such as HANDLE. This means that a Windows programmer needs to cast// values when using _beginthreadex. Since this is terribly inconvenient, // I created this macro to perform the casting.typedef unsigned (__stdcall *PTHREAD_START) (void *);#define chBEGINTHREADEX(psa, cbStackSize, pfnStartAddr, \ pvParam, dwCreateFlags, pdwThreadId) \ ((HANDLE)_beginthreadex( \ (void *) (psa), \ (unsigned) (cbStackSize), \ (PTHREAD_START) (pfnStartAddr), \ (void *) (pvParam), \ (unsigned) (dwCreateFlags), \ (unsigned *) (pdwThreadId)))// Sets the dialog box iconsinline void chSETDLGICONS(HWND hWnd, int idi) { SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM) LoadIcon((HINSTANCE) GetWindowLongPtr(hWnd, GWLP_HINSTANCE), MAKEINTRESOURCE(idi))); SendMessage(hWnd, WM_SETICON, ICON_SMALL, (LPARAM) LoadIcon((HINSTANCE) GetWindowLongPtr(hWnd, GWLP_HINSTANCE), MAKEINTRESOURCE(idi)));}

 

BOOL Dlg_OnInitDialog(HWND hWnd, HWND hWndFocus, LPARAM lParam){	chSETDLGICONS(hWnd, IDI_QUEUE);	return TRUE;}void Dlg_OnCommand(HWND hWnd, int id, HWND hWndCtl, UINT codeNotify){	switch (id)	{	case IDCANCEL:		EndDialog(hWnd, id);		break;	}}INT_PTR WINAPI Dlg_Proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam){	switch (uMsg)	{		chHANDLE_DLGMSG(hWnd, WM_INITDIALOG, Dlg_OnInitDialog);		chHANDLE_DLGMSG(hWnd, WM_COMMAND,	 Dlg_OnCommand);	}	return FALSE;}/*************************************************************************/int WINAPI _tWinMain(HINSTANCE hInstExe, HINSTANCE, PTSTR pszCmdLine, int){	DialogBox(hInstExe, MAKEINTRESOURCE(IDD_QUEUE), NULL, Dlg_Proc);	return 0;}

 

2.线程安全队列的实现

 

 

/* * File:	CQueue.h * Time:	2013-07-10 * 描述:	学习《Windows核心编程》 */#ifndef _CQUEUE_H_#define _CQUEUE_H_#include 
class CQueue{public: struct ELEMENT { int m_nThreadNum; // 线程号 int m_nRequestNum; // 请求号 }; typedef ELEMENT* PELEMENT;private: PELEMENT m_pElements; // 队列元素数组 int m_nMaxElements; // 数组长度 HANDLE m_h[2]; // 两个内核对象,一个互斥量一个信号量 HANDLE &m_hmtxQ; // 互斥量对象的引用 HANDLE &m_hsemNumElements; // 信号量对象的引用public: CQueue(int nMaxElements); ~CQueue(); BOOL Append(PELEMENT pElement, DWORD dwMilliseconds); BOOL Remove(PELEMENT pElement, DWORD dwMilliseconds);};#endif

 

/************************************************************************/CQueue::CQueue(int nMaxElements) : m_hmtxQ(m_h[0]), m_hsemNumElements(m_h[1]){	// 初始化结构数组	m_pElements = (PELEMENT)HeapAlloc(GetProcessHeap(), 0, sizeof(ELEMENT) * nMaxElements);	// 初始化数组长度	m_nMaxElements = nMaxElements;	// 创建互斥量和信号量内核对象	m_hmtxQ = CreateMutex(NULL, FALSE, NULL);	m_hsemNumElements = CreateSemaphore(NULL, 0, nMaxElements, NULL);}CQueue::~CQueue(){	// 清理内核对象和内存	CloseHandle(m_hsemNumElements);	CloseHandle(m_hmtxQ);	HeapFree(GetProcessHeap(), 0, m_pElements);}BOOL CQueue::Append(CQueue::PELEMENT pElement, DWORD dwTimeout){	BOOL fOk = FALSE;	// 等待互斥量内核对象	DWORD dw = WaitForSingleObject(m_hmtxQ, dwTimeout);	// 返回WAIT_OBJECT_0表示得到了队列的独占访问权	if (dw == WAIT_OBJECT_0) {		LONG lPrevCount;		// 尝试向队列添加新元素		fOk = ReleaseSemaphore(m_hsemNumElements, 1, &lPrevCount);		// fOk为TRUE表示队列没满,可以添加新元素		if (fOk) {			m_pElements[lPrevCount] = *pElement;		}		else {			SetLastError(ERROR_DATABASE_FULL);		}		// 释放互斥量,允许其他线程访问队列		ReleaseMutex(m_hmtxQ);	}	else {		SetLastError(ERROR_TIMEOUT);	}	return fOk;}BOOL CQueue::Remove(CQueue::PELEMENT pElement, DWORD dwTimeout){	// 确保对队列具有独占访问权,且要求队列中有元素可取	// 等待信号量成功的副作用使它的计数减一,所以不需要显示调用ReleaseSemaphore()	BOOL fOk = (WaitForMultipleObjects(_countof(m_h), m_h, TRUE, dwTimeout) == WAIT_OBJECT_0);		if (fOk)	{		// 获取元素		*pElement = m_pElements[0];		// 取出索引为0 的元素,把数组中剩余元素向前挪一个位置		MoveMemory(&m_pElements[0], &m_pElements[1], sizeof(ELEMENT) * (m_nMaxElements - 1));		// 释放互斥量,允许其他线程访问队列		ReleaseMutex(m_hmtxQ);	}	else	{		SetLastError(ERROR_TIMEOUT);	}	return fOk;}

 

 

3.客户端线程

 

 

CQueue				g_q(10);volatile LONG		g_fShutdown = FALSE;HWND				g_hWnd;// Handles to all reader/writer threadsHANDLE g_hThreads[MAXIMUM_WAIT_OBJECTS];// Number of reader/writer threads  int    g_nNumThreads = 0;/************************************************************************/DWORD WINAPI ClientThread(PVOID pvParam){	int nThreadNum = PtrToUlong(pvParam);			// 线程号	HWND hWndLB = GetDlgItem(g_hWnd, IDC_CLIENT);	int nRequestNum = 0;	while (1 != InterlockedCompareExchange(&g_fShutdown, 0, 0))	{		nRequestNum++;				TCHAR sz[1024];		CQueue::ELEMENT e = { nThreadNum, nRequestNum };		// 尝试添加元素到队列		if (g_q.Append(&e, 200)) {			StringCchPrintf(sz, _countof(sz), TEXT("客户线程%d 添加元素%d"), nThreadNum, nRequestNum);		}		else {			StringCchPrintf(sz, _countof(sz), TEXT("客户线程%d 添加元素%d失败(%s)"), nThreadNum, nRequestNum,				(GetLastError() == ERROR_TIMEOUT) ? TEXT("超时") : TEXT("队列已满"));		}		ListBox_SetCurSel(hWndLB, ListBox_AddString(hWndLB, sz));		Sleep(2500);	}	return 0;}

 

BOOL Dlg_OnInitDialog(HWND hWnd, HWND hWndFocus, LPARAM lParam){	chSETDLGICONS(hWnd, IDI_QUEUE);	g_hWnd = hWnd;	DWORD dwThreadID;	// 创建客户端线程	for (int i = 0; i < 4; i++)		g_hThreads[g_nNumThreads++] = chBEGINTHREADEX(NULL, 0, ClientThread, (PVOID)(INT_PTR) i, 0, &dwThreadID);	return TRUE;}

 

4.服务器端线程

 

DWORD WINAPI ServerThread(PVOID pvParam){	int nThreadNum = PtrToUlong(pvParam);	HWND hWndLB = GetDlgItem(g_hWnd, IDC_SERVER);	while (1 != InterlockedCompareExchange(&g_fShutdown, 0, 0)) {		TCHAR sz[1024];		CQueue::ELEMENT e;		// 尝试移除元素		if (g_q.Remove(&e, 5000)) {			StringCchPrintf(sz, _countof(sz), TEXT("服务器端线程%d移除客户端线程%d放入的元素%d"), nThreadNum, e.m_nThreadNum, e.m_nRequestNum);			Sleep(2000 * e.m_nThreadNum);		}		else {			StringCchPrintf(sz, _countof(sz), TEXT("服务器端线程%d 没有元素可取"), nThreadNum);		}		ListBox_SetCurSel(hWndLB, ListBox_AddString(hWndLB, sz));	}	return 0;}

 

BOOL Dlg_OnInitDialog(HWND hWnd, HWND hWndFocus, LPARAM lParam){	chSETDLGICONS(hWnd, IDI_QUEUE);	g_hWnd = hWnd;	DWORD dwThreadID;	// 创建客户端线程	for (int i = 0; i < 4; i++)		g_hThreads[g_nNumThreads++] = chBEGINTHREADEX(NULL, 0, ClientThread, (PVOID)(INT_PTR) i, 0, &dwThreadID);	// 创建读者线程	for (int i = 0; i < 2; i++)		g_hThreads[g_nNumThreads++] = chBEGINTHREADEX(NULL, 0, ServerThread, (PVOID)(INT_PTR) i, 0, &dwThreadID);	return TRUE;}

 

int WINAPI _tWinMain(HINSTANCE hInstExe, HINSTANCE, PTSTR pszCmdLine, int){	DialogBox(hInstExe, MAKEINTRESOURCE(IDD_QUEUE), NULL, Dlg_Proc);	InterlockedExchange(&g_fShutdown, TRUE);	WaitForMultipleObjects(g_nNumThreads, g_hThreads, TRUE, INFINITE);	while (g_nNumThreads--)		CloseHandle(g_hThreads[g_nNumThreads]);	return 0;}

 

 

转载于:https://www.cnblogs.com/jiangu66/p/3184783.html

你可能感兴趣的文章
Android应用程序文件缓存getCacheDir()和getExternalCacheDir()
查看>>
spring事务失效
查看>>
线段树入门( 转 )
查看>>
浅谈 JSON.stringify 方法
查看>>
不同手机根据坐标计算控件、图片的像素,px 与 dp, sp换算公式?
查看>>
XML深度解析
查看>>
根据一个整齐的数据,随机的得到一个新的数组,可指定数组元素出现的位置
查看>>
转载 JS获取当前手机浏览器可视区域大小
查看>>
操作系统学习---内存管理
查看>>
SpringMyBatis解析2-SqlSessionFactoryBean
查看>>
按照excel文档中的内容在当前cad图纸中自动排布实体
查看>>
Winform开发框架之图表报表在线设计器2-图表-SNF.EasyQuery项目--SNF快速开发平台3.3-Spring.Net.Framework...
查看>>
C#基础第八天-作业-设计类-面向对象方式实现两个帐户之间转账
查看>>
洛谷 P3237 [HNOI2014]米特运输
查看>>
Attributes.Add用途与用法
查看>>
JavaScript面向对象初探——封装和继承
查看>>
L2-001 紧急救援 (dijkstra+dfs回溯路径)
查看>>
【概率】poj 2096:Collecting Bugs
查看>>
javascript 无限分类
查看>>
【自制插件】MMD4Maya
查看>>