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