建立一个基于对话框的工程MultiThread3,在对话框IDD_MULTITHREAD3_DIALOG中加入一个编辑框IDC_MILLISECOND,一个按钮IDC_START,标题为“开始”
,一个进度条IDC_PROGRESS1;打开ClassWizard,为编辑框IDC_MILLISECOND添加int型变量m_nMilliSecond,为进度条IDC_PROGRESS1添加CProgressCtrl型变量
m_ctrlProgress;
在MultiThread3Dlg.h文件中添加一个结构的定义: struct threadInfo
{
UINT nMilliSecond;
CProgressCtrl* pctrlProgress;
};
线程函数的声明: UINT ThreadFunc(LPVOID lpParam);
注意,二者应在类CMultiThread3Dlg的外部。
在类CMultiThread3Dlg内部添加protected型变量: HANDLE hThread;
DWORD ThreadID;
分别代表线程的句柄和ID。
在MultiThread3Dlg.cpp文件中进行如下操作:
定义公共变量 threadInfo Info;
双击按钮IDC_START,添加相应消息处理函数:void CMultiThread3Dlg::OnStart()
{
// TODO: Add your control notification handler code here
UpdateData(TRUE);
Info.nMilliSecond=m_nMilliSecond;
Info.pctrlProgress=&m_ctrlProgress;
hThread=CreateThread(NULL,
0,
(LPTHREAD_START_ROUTINE)ThreadFunc,
&Info,
0,
&ThreadID);
}
在函数BOOL CMultiThread3Dlg::OnInitDialog()中添加语句: {
……
// TODO: Add extra initialization here
m_ctrlProgress.SetRange(0,99);
m_nMilliSecond=10;
UpdateData(FALSE);
return TRUE; // return TRUE unless you set the focus to a control
}
添加线程处理函数:UINT ThreadFunc(LPVOID lpParam) {
threadInfo* pInfo=(threadInfo*)lpParam;
for(int i=0;i<100;i++)
{
int nTemp=pInfo->nMilliSecond;
pInfo->pctrlProgress->SetPos(i);
Sleep(nTemp);
}
return 0;
}
顺便补充一点,如果你在void CMultiThread3Dlg::OnStart() 函数中添加语句,编译运行你就会发现进度条不进行刷新,主线程也停止了反应。什么原因呢?这是因为WaitForSingleObject函数等待子线程(ThreadFunc)结束时,导致了线程死锁。因为WaitForSingleObject函数会将主线程挂起(任何消息都得不到处理),而子线程ThreadFunc正在设置进度条,一直在等待主线程将刷新消息处理完毕返回才会检测通知事件。这样两个线程都在互相等待,死锁发生了,编程时应注意避免
在此例程基础上加入启动线程前把Start按钮设为FALSE, 线程工作完成后再把Start按钮设为TRUE,首先尝试在OnButtonStart()中加入下面的代码:
GetDlgItem(IDC_START)->EnableWindow(FALSE);
WaitForSingleObject(hThread, INFINITE);
GetDlgItem(IDC_START)->EnableWindow(TRUE);
会出现上文提到的死锁现象,解决方法如下:
第一种:
在ThreadFunc(LPVOID lParam)函数return前加入
AfxGetMainWnd()->GetDlgItem(IDC_START)->EnableWindow(TRUE);
第二种:
在.cpp文件中定义全局指针CMultiThread3Dlg* g_pDlg;
在OnInitDialog()中增加 g_pDlg = this;
在ThreadFunc(LPVOID lParam)函数return前加入
g_pDlg->GetDlgItem(IDC_START)->EnableWindow(TRUE);
以上两种方法在VC6中测试可行,但是个人感觉安全性不高,下面是第三种方法
在.h头文件中class前加入自定义消息 #define WM_START_STATUS WM_USER+101
在.h的protected下定义消息处理函数 afx_msg void OnStartStatus(WPARAM wParam, LPARAM lParam);
在.cpp的MESSAGE_MAP中增加 ON_MESSAGE(WM_START_STATUS, OnStartStatus)
在ThreadFunc(LPVOID lParam)函数return前加入
SendMessage(AfxGetMainWnd()->m_hWnd, WM_START_STATUS, TRUE, 0);
在.cpp中增加消息处理函数:
void CMultiThread3Dlg::OnStartStatus(WPARAM wParam, LPARAM lParam)
{
BOOL bStatus = (BOOL)wParam;
GetDlgItem(IDC_START)->EnableWindow(bStatus);
}
个人感觉第三种方法的安全性要比前两种都好