MFC之线程(开启、挂起、恢复、终止)

31 篇文章 7 订阅

MFC之线程(开启、挂起、恢复、终止)

MFC中线程有UI线程和工作者线程两种,下面分享一下MFC工作者线程的相关操作,包括线程的开启、挂起、恢复和终止。

流程:1.列举用法
2.案例展示

一:MFC线程的开启

CWinThread* AfxBeginThread(

   AFX_THREADPROC  pfnThreadProc,  //线程的入口函数

   LPVOID  pParam,   //传递入线程的参数,类型为:LPVOID,可以是结构体

   int nPriority = THREAD_PRIORITY_NORMAL,  //优先级,一般为 0 :和主线程具有相同的优先级.

   UINT nStackSize = 0,  //指定新创建的线程的栈大小。0:栈和主线程一样的大小
   
   DWORD dwCreateFlags = 0,  //默认值0:创建线程后立即运行,若是CREATE_SUSPENDED:线程创建后处于挂起状态,直到调用ResumeThread()函数。

   LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL  //指定新线程的安全属性,默认值NULL:新线程具有和主线程一样的安全性。

);

二 :MFC线程的挂起

CwinThread::SuspendThread();

三 :MFC线程的恢复

CwinThread::ResumeThread():让挂起的线程继续执行。

主意:每个线程,系统都维持一个“计数器”,suspendThread加1,resumeThread减1,只有计数器为0时,才会给线程调度处理时间。

三 :MFC线程的终止

1. WaitForSingleObject //等待一个进程结束

  DWORD WaitForSingleObject( 
  HANDLE hHandle,    //指明一个内核对象的句柄
  DWORD dwMilliseconds //等待时间(毫秒)
  ); 
  该函数需要传递一个内核对象句柄,该句柄标识一个内核对象,若该内核对象处于未通知状态,则该函数导致线程进入阻塞状态;若该内核对象处于已通知状态,则该函数立即返回WAIT_OBJECT_0。
  第二个参数:1--INFINITE:指明要无限期等待下去,
             2--0:函数测试同步对象的状态并立即返回。若等待超时,该函数返回WAIT_TIMEOUT。
                                                 若该函数失败,返回WAIT_FAILED。
例:
DWORD dword = WaitForSingleObject(hProcess, 5000); //等待一个进程结束
switch (dword)
{
case WAIT_OBJECT_0: // hProcess所代表的进程在5秒内结束
break;

case WAIT_TIMEOUT: // 等待时间超过5秒
break;

case WAIT_FAILED: // 函数调用失败,比如传递了一个无效的句柄
break;
}

2. WaitForMultipleObjects //等待多个内核对象变为已通知状态

DWORD WaitForMultipleObjects(
DWORD dwCount,           //等待内核对象的个数
CONST HANDLE* phObjects, //存放被等待的内核对象句柄的数组
BOOL bWaitAll,           //是否等到所有内核对象为已通知状态后才返回
DWORD dwMilliseconds     //等待时间
);
注意:bWaitAll参数:
		TRUE:只有当等待的所有内核对象为已通知状态时函数才返回:WAIT_OBJECT_0
		FALSE:只要一个内核对象为已通知状态该函数就返回,	成功则返回值指明是哪个内核对象收到通知。
	该函数失败:返回WAIT_FAILED
	      超时:返回WAIT_TIMEOUT

例:
//2个进程句柄
HANDLE hHandle[2] = {m_pthreadThreadMainCheck->m_hThread,m_pthreadEyeFor24->m_hThread};
DWORD dword = WaitForMultipleObjects(2, hHandle, FALSE, 5000); //等待3个进程结束

switch (dword)
{
case WAIT_FAILED:// 函数呼叫失败
break;

case WAIT_TIMEOUT:// 超时
break;

case WAIT_OBJECT_0 + 0:// hHandle[0]所代表的进程结束
break;

case WAIT_OBJECT_0 + 1:// hHandle[1]所代表的进程结束
break;
}

案例:

1.建立MFC对话框工程Thread,布局如下:
在这里插入图片描述
2.为3个列表框关联变量,控件类型,如下:在这里插入图片描述
3.添加9个按钮。
4.在ThreadDlg.h中创建2个线程对象,并声明2个线程函数:

class CThreadDlg : public CDialog
{
public:
	CThreadDlg(CWnd* pParent = NULL);	// standard constructor
	//XXXX
	//默认代码
	//XXXX
public:
	
		BOOL bstopAllThread;
		BOOL bPause;
		BOOL bEye24Stop;

		CWinThread *m_pthreadThreadMainCheck;
		CWinThread *m_pthreadEyeFor24;

		static UINT ThreadMainCheck(LPVOID lpParam);
		void DoThreadMainCheck();

		static UINT ThreadEyeFor24(LPVOID lpParam);
		void DoEyeFor24();
		
		CString GetInfomation(CString info);
	//XXXX
	//默认代码
	//XXXX

5.在CThreadDlg.cpp类中BOOL CThreadDlg::OnInitDialog()中开启线程:

BOOL CThreadDlg::OnInitDialog()
{
	CDialog::OnInitDialog();
	//XXXX
	//默认代码
	//XXXX
	
	// TODO: Add extra initialization here
	//初始化相关变量
        bstopAllThread=FALSE;
	    bPause = FALSE;
	    bEye24Stop = FALSE;
	    
	  //初始化线程变量
		m_pthreadThreadMainCheck = NULL;
		m_pthreadEyeFor24 = NULL;
		
		//开启线程:默认挂起,
		m_pthreadThreadMainCheck = AfxBeginThread(&ThreadMainCheck,this,THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED,NULL);
		m_pthreadThreadMainCheck->m_bAutoDelete = FALSE;
		m_pthreadThreadMainCheck->ResumeThread();

		m_pthreadEyeFor24 = AfxBeginThread(&ThreadEyeFor24,this,THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED,NULL);
		m_pthreadEyeFor24->m_bAutoDelete = FALSE;
		m_pthreadEyeFor24->ResumeThread();
	//XXXX
	//默认代码
	//XXXX

	return TRUE;  // return TRUE  unless you set the focus to a control
}
注意:AfxBeginThread返回的CWinThread的对象指针所指的对象在默认情况下会自动删除。
            当设置pThread-> m_bAutoDelete=FALSE;线程退出时是否需要delete 线程对象,
			默认为TRUE时线程自动delete
			

6.在CThreadDlg.cpp中实现线程函数

BOOL bSendMessage = FALSE;
CString infomation;
//获取信息
CString CThreadDlg:: GetInfomation(CString info)
{
	infomation = info;
	return infomation;

}

//主线程:监测有没有信息要输出到列表框中
UINT CThreadDlg::ThreadMainCheck(LPVOID lpParam)
{

	CThreadDlg *pCThreadDlg = (CThreadDlg *) lpParam;
	if (pCThreadDlg)
	{
		pCThreadDlg->DoThreadMainCheck();
	}

	return 0;
}
//主线程内部调用的函数,具体实现
void CThreadDlg::DoThreadMainCheck()
{
	while(TRUE)
	{

		if (bstopAllThread)
		{
			break;
		}

		if (bSendMessage)
		{

			SYSTEMTIME LocalSystemTime;
			GetLocalTime(&LocalSystemTime);
			CString strText;
			strText.Format(_T("%02d:%02d:%02d:"),LocalSystemTime.wHour,LocalSystemTime.wMinute,LocalSystemTime.wSecond);

			
			m_ListBoxWarningInfo.InsertString(0,strText + infomation);
			m_ListBoxWarningInfo.SetCurSel(0);
			
			
			while(m_ListBoxWarningInfo.GetCount() > 10)
			{
				m_ListBoxWarningInfo.DeleteString(m_ListBoxWarningInfo.GetCount()-1);

			}
			
		}

	}
	
}

//电子眼线程:一直检测主线程有没有被挂起或恢复,根据具体情况更新线程状态
UINT CThreadDlg:: ThreadEyeFor24(LPVOID lpParam)
{
	CThreadDlg *pThreadDlg = (CThreadDlg*)lpParam;
	if (pThreadDlg)
	{
		pThreadDlg->DoEyeFor24();
	}

	return 0;
}
void  CThreadDlg:: DoEyeFor24()
{
	while(TRUE)
	{

		if (bEye24Stop || bstopAllThread)
		{
			break;
		}
		if (bPause)
		{	
			SYSTEMTIME LocalSystemTime;
			GetLocalTime(&LocalSystemTime);
			CString strText;
			strText.Format(_T("%02d:%02d:%02d:"),LocalSystemTime.wHour,LocalSystemTime.wMinute,LocalSystemTime.wSecond);

			m_Eye24.DeleteString(1);
			m_Eye24.InsertString(1,strText + "状态信息监测线程已暂停");
			m_Eye24.SetCurSel(1);
			Sleep(1000);
		}else{

			SYSTEMTIME LocalSystemTime;
			GetLocalTime(&LocalSystemTime);
			CString strText;
			strText.Format(_T("%02d:%02d:%02d:"),LocalSystemTime.wHour,LocalSystemTime.wMinute,LocalSystemTime.wSecond);

			m_Eye24.DeleteString(1);
			m_Eye24.InsertString(1,strText + "状态信息监测线程已恢复");
			m_Eye24.SetCurSel(1);
			Sleep(1000);


		}
		
		m_Eye24.DeleteString(0);
		m_Eye24.InsertString(0,"24小时电子眼监控中...");
		

	}
}

7.为每个按钮添加事件:


//雪糕类
void CThreadDlg::OnIceCream() 
{

	bSendMessage = TRUE;
	GetInfomation(_T("正被光顾:雪糕类"));
	bSendMessage = FALSE;

	CIceCream mCIceCream ;
	mCIceCream.DoModal();
	
}
//冰沙类
void CThreadDlg::OnSorbet() 
{
	bSendMessage = TRUE;
	GetInfomation(_T("正被光顾:冰沙类"));
	bSendMessage = FALSE;

	CSorbet mCSorbet;
	mCSorbet.DoModal();
	
}

//奶茶类
void CThreadDlg::OnMilkyTea() 
{
	bSendMessage = TRUE;
	GetInfomation(_T("正被光顾:奶茶类"));
	bSendMessage = FALSE;

	CMilkyTea m_MilkyTea;
	m_MilkyTea.DoModal();

}

//暂停信息检测线程
void CThreadDlg::OnPauseMessage() 
{
	bPause = TRUE;
	m_pthreadThreadMainCheck->SuspendThread();
	
}
//恢复信息检测线程
void CThreadDlg::OnResumeMessage() 
{
	bPause = FALSE;
	m_pthreadThreadMainCheck->ResumeThread();
}

//下单按钮1:特色风味1
void CThreadDlg::OnSpecialItem1() 
{
	m_Order.InsertString(0,"特色风味:海南椰香奶茶 1份");
	m_Order.SetCurSel(0);
}
//下单按钮2:特色风味2
void CThreadDlg::OnSpecialItem2() 
{
	
	m_Order.InsertString(0,"特色风味:台式奶茶 1份");
	m_Order.SetCurSel(0);

}
//下单按钮3:特色风味3
void CThreadDlg::OnSpecialItem3() 
{
	
	m_Order.InsertString(0,"特色风味:土耳其奶茶 1份");
	m_Order.SetCurSel(0);

}

8.最后,线程结束是需要清理线程对象:

void CThreadDlg::OnDestroy() 
{
	CDialog::OnDestroy();
	
	bstopAllThread = TRUE;
	bPause = TRUE;
	bEye24Stop = TRUE;
	
	HANDLE hHandle[2] = {m_pthreadThreadMainCheck->m_hThread,m_pthreadEyeFor24->m_hThread};
	while (TRUE)
	{
		
		DWORD dwObjects = WaitForMultipleObjects(2,hHandle,TRUE,0);
		if (dwObjects == WAIT_OBJECT_0)
		{
			break;
		}
		else{

			MSG msg;
			if (::PeekMessage(&msg,NULL,0,0,PM_NOREMOVE))
			{
				AfxGetApp()->PumpMessage();
			}

		}
	}

//清理线程对象
	delete m_pthreadThreadMainCheck;
	m_pthreadThreadMainCheck = NULL;
	
	delete m_pthreadEyeFor24;
	m_pthreadEyeFor24 = NULL;
}


这样,程序运行后,点击按钮“雪糕”,“冰沙”,“奶茶”时,左边第一个列表框中将更新显示,全程由主线程控制着,如图:
在这里插入图片描述
当按下“暂停信息”按钮时再点击上面三个按钮时,第一个列表框无法继续更新显示信息,因为“暂停信息”自行了线程挂起操作
m_pthreadThreadMainCheck->SuspendThread();
如图:
在这里插入图片描述
此时再点击“恢复信息”按钮,再按下上面“雪糕”,“沙冰”和“奶茶”按钮时,信息又可以再次更新实时信息。因为“恢复信息”按钮执行了线程的恢复操作:
m_pthreadThreadMainCheck->ResumeThread();

以上就是通过2个线程模拟奶茶店系统的过程,包含了形成的基本相关操作。
至于中间订单列表框和下单的按钮,则没有用到线程,只是通过按钮显示而已,衬托的作用。

结语:谢谢!

  • 9
    点赞
  • 77
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

随心漂流

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值