[MFC]同步对象——CEvent事件,CMutex互斥量

实例——CEvent事件

头文件关键代码:
// MFCEventDlg.h : 头文件
#pragma once
#define WM_MSG WM_USER+1
typedef struct THREAD_PARAM
{
	HWND hWnd;
	int nData;
	CEvent* pEvent;
}_THREAD_PARAM;
UINT ThreadFun(LPVOID pParam);
class CMFCEventDlg : public CDialogEx
{
	//...
	//定义的成员变量
	THREAD_PARAM mThreadParam;
	CWinThread* pThread;
	// ...
};
cpp文件关键代码:
// MFCEventDlg.cpp : 实现文件
CMFCEventDlg::CMFCEventDlg(CWnd* pParent /*=NULL*/)
	: CDialogEx(CMFCEventDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
	pThread=NULL;
	mThreadParam.nData=0;
	mThreadParam.pEvent=new CEvent(TRUE,FALSE,L"eventDlg");
	//new CEvent(BOOL bInitiallyOwn = FALSE,BOOL bManualReset = FALSE,LPCTSTR lpszName = NULL,);  
	//bInitiallyOwn:如果为TRUE,CMultilock或CSingleLock对象的线程可用;如果为FALSE,所有要访问资源的线程必须等待。
	//bManualReset:如果为TRUE,指定事件是一个手工事件,否则事件是一个自动事件。 
	//lpszName:CEvent事件的名字
	//要访问或释放一个CEvent对象,可建立一个CSingleLock或CMultiLock对象并调用其Lock和Unlock成员函数。	要将CEvent对象的状态改为已标记(无须等待的线程),可调用SetEvent或PulseEvent。要设置一个CEvent对象为无标记(必须等待的线程),可调用ResetEvent。
}
CMFCEventDlg::~CMFCEventDlg()
{
	if (pThread)
	{
		mThreadParam.pEvent->SetEvent();//设置事件
		WaitForSingleObject(pThread->m_hThread,INFINITE);//等待线程结束
		delete pThread;
		pThread=NULL;
	}
	if (mThreadParam.pEvent)
	{
		delete mThreadParam.pEvent;
		mThreadParam.pEvent=NULL;
	}
}

BEGIN_MESSAGE_MAP(CMFCEventDlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_BUTTON_START, &CMFCEventDlg::OnBnClickedButtonStart)
	ON_BN_CLICKED(IDC_BUTTON_STOP, &CMFCEventDlg::OnBnClickedButtonStop)
	ON_MESSAGE(WM_MSG,&CMFCEventDlg::OnMsgFun)
END_MESSAGE_MAP()


//WM_MSG消息函数
LRESULT CMFCEventDlg::OnMsgFun(WPARAM wParam,LPARAM lParam)
{
	SetDlgItemInt(IDC_EDIT_DATA,mThreadParam.nData);
	return 0;
}
//启动线程按钮事件函数
void CMFCEventDlg::OnBnClickedButtonStart()
{ 
	if (pThread)
	{
		AfxMessageBox(_T("线程已经启动。"));
		return;
	}
	mThreadParam.hWnd=m_hWnd;
	mThreadParam.pEvent->ResetEvent();//重置事件
	pThread=AfxBeginThread(ThreadFun,&mThreadParam,THREAD_PRIORITY_ABOVE_NORMAL,0,CREATE_SUSPENDED);
	pThread->m_bAutoDelete=FALSE;//线程结束后不自动消失
	pThread->ResumeThread();//调用这个函数以使被SuspendThread成员函数所挂起的线程恢复执行,或者使用CREATE_SUSPENDED标志创建的线程恢复执行。当前线程的挂起计数被减小1。如果挂起计数被减小到0,线程将恢复执行;否则线程继续被挂起。
}
//停止线程按钮事件函数
void CMFCEventDlg::OnBnClickedButtonStop()
{ 
	if (pThread==NULL)
	{
		AfxMessageBox(_T("线程已经停止。"));
		return;
	}
	mThreadParam.pEvent->SetEvent();
	::WaitForSingleObject(pThread->m_hThread,INFINITE);
	delete pThread;
	pThread=NULL;
}
//线程函数
UINT ThreadFun(LPVOID pParam)
{
	THREAD_PARAM* pThread=(THREAD_PARAM*)pParam;
	while(TRUE)
	{
		if (::WaitForSingleObject(pThread->pEvent->m_hObject,0) == WAIT_OBJECT_0)
		{
			break;
		}
		Sleep(100);
		pThread->nData++;
		::PostMessage(pThread->hWnd,WM_MSG,0,0);
	} 
	return 0;
}

效果图:

实例——CMutex互斥量

互斥量与临界区很相似,但是使用时相对复杂一些,它不仅可以在同一应用程序的线程间实现同步,还可以在不同的进程间实现同步,从而实现资源的安全共享。互斥量与CMutex类的对象相对应,使用互斥对象时,必须创建一个CSingleLockCMultiLock对象,用于实际的访问控制,该对象的Lock()函数用于占有互斥,Unlock()函数用于释放互斥。

头文件关键代码:
// MFCMutaxDlg.h : 头文件 
#pragma once
#define  WM_MSG WM_USER+1
typedef struct THREAD_PARAM
{
	HWND hWnd;
	int nData;
	CMutex* pMutex;
}_THREAD_PARAM;
UINT ThreadFun1(LPVOID pParam);
UINT ThreadFun2(LPVOID pParam);

cpp文件关键代码:
// MFCMutaxDlg.cpp : 实现文件
CMFCMutaxDlg::CMFCMutaxDlg(CWnd* pParent /*=NULL*/)
	: CDialogEx(CMFCMutaxDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
	///定义的成员变量
// 	THREAD_PARAM mThreadParam;
// 	CWinThread* pThread1;
// 	CWinThread* pThread2;
	pThread1=NULL;
	pThread2=NULL;
	mThreadParam.nData=0;
	mThreadParam.pMutex=new CMutex();
	//CMutex( BOOL bInitiallyOwn = FALSE, LPCTSTR lpszName = NULL, LPSECURITY_ATTRIBUTES lpsaAttribute = NULL );
	/*
	bInitiallyOwn 指定是否创建了CMutex对象的线程最初拥有由哑程控制资源的访问权。  
	lpszNameCMutex 对象的名称。若其它的哑程由同样的名称,那么必须提供lpszName,以便对象能够通过进程边界。若该值为NULL,那么哑程将没有命名。若该名称匹配已经存在的哑程,那么构造函数将创建一个参考哑程名称的新CMutex对象。若该名称匹配已存在的不是哑程的同步对象,那么构造过程将失败。  
	lpsaAttribute 哑程对象的安全性。如果需要该结构的完整描述,请参阅“Win32程序员参考”中的SECURITY_ATTRIBUTES。  
	说明:
	构造一个命名的或未命名的CMutex对象,若要访问或释放CMutex对象,那么请创建CMultiLock或CSingleLock 对象,并调用Lock或Unlock成员函数。若CMutex对象被独占使用,那么调用Unlock成员函数释放它。 
	*/
}
CMFCMutaxDlg::~CMFCMutaxDlg()
{
	if (pThread1)
	{
		::WaitForSingleObject(pThread1->m_hThread,INFINITE);
		delete pThread1;
		pThread1=NULL;
	}
	if (pThread2)
	{
		::WaitForSingleObject(pThread2->m_hThread,INFINITE);
		delete pThread2;
		pThread2=NULL;
	}
	if (mThreadParam.pMutex)
	{
		delete mThreadParam.pMutex;
		mThreadParam.pMutex=NULL;
	}
}

BEGIN_MESSAGE_MAP(CMFCMutaxDlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_BUTTON_START, &CMFCMutaxDlg::OnBnClickedButtonStart)
	ON_MESSAGE(WM_MSG,&CMFCMutaxDlg::OnMsgFun)
END_MESSAGE_MAP()

//WM_MSG消息函数,其格式是:LRESULT Fun(WPARAM wParam,LPARAM lParam)
LRESULT CMFCMutaxDlg::OnMsgFun(WPARAM wParam,LPARAM lParam)
{
	SetDlgItemInt(IDC_EDIT_DATA,mThreadParam.nData);
	return 0;
}
//开始线程按钮事件
void CMFCMutaxDlg::OnBnClickedButtonStart()
{
	if (pThread1 !=NULL)//只执行一次ThreadFun,去掉中间3行
	{
		AfxMessageBox(_T("线程已经启动。"));
		::WaitForSingleObject(pThread1->m_hThread,INFINITE);
		delete pThread1;
		pThread1=NULL;
		return;
	} 
	if (pThread2)//可以执行多次ThreadFun
	{
		DWORD exitCode=0;
		if (::GetExitCodeThread(pThread2->m_hThread,&exitCode))
		{
			if (exitCode == STILL_ACTIVE)
			{
				AfxMessageBox(_T("线程2已经启动。"));
				return ;
			}
			else
			{
				delete pThread2;
				pThread2=NULL;
			}
		}
	}
	mThreadParam.hWnd=m_hWnd;
	pThread1=AfxBeginThread(ThreadFun1,&mThreadParam,THREAD_PRIORITY_ABOVE_NORMAL,0,CREATE_SUSPENDED);
	pThread2=AfxBeginThread(ThreadFun2,&mThreadParam,THREAD_PRIORITY_ABOVE_NORMAL,0,CREATE_SUSPENDED);
	pThread1->m_bAutoDelete=FALSE;
	pThread2->m_bAutoDelete=FALSE;
	pThread1->ResumeThread();
	pThread2->ResumeThread();
}
//线程函数1
UINT ThreadFun1(LPVOID pParam)
{
	THREAD_PARAM* pThreadParam=(THREAD_PARAM*)pParam;
	CSingleLock sigleLock(pThreadParam->pMutex,TRUE);
	/*
	CSingleLock( CSyncObject* pObject, BOOL bInitialLock = FALSE );
	参数: pObject 指向要被访问的同步对象。不能是NULL。  
	bInitialLock 指示是否要在最初尝试访问所提供的对象。   
	此成员函数用来构造一个CSingleLock对象。通常是从被控制资源的一个访问成员函数中来调用这个函数。 
	*/
	if (sigleLock.IsLocked())//使用前要加锁
	{
		for (int i=0;i<10;i++)
		{
			pThreadParam->nData++;
			::PostMessage(pThreadParam->hWnd,WM_MSG,0,0);
			Sleep(200);
		}
		sigleLock.Unlock();//使用后要解锁
	}
	return 0;
}
//线程函数2
UINT ThreadFun2(LPVOID pParam)
{
	THREAD_PARAM* pThreadParam=(THREAD_PARAM*)pParam;
	CSingleLock singleLock(pThreadParam->pMutex);
	singleLock.Lock();
	if (singleLock.IsLocked())
	{
		for (int i=0;i<10;i++)
		{
			pThreadParam->nData--;
			::PostMessage(pThreadParam->hWnd,WM_MSG,0,0);
			Sleep(100);				
		}
		singleLock.Unlock();
	}
	return 0;
}

效果图:
已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页