我正在学习线程和多线程..所以我刚刚创建了一个小应用程序,我将在其中更新
进度条和使用线程的静态文本。我从用户那里得到两个输入,开始值和结束值
循环应该旋转多长时间。我的应用程序中有 2 个线程。
Thread1-更新进度条(根据循环)将显示计数(循环计数)的静态文本。
Thread2 - 更新另一个仅显示名称的静态文本
基本上,如果用户单击开始,进度条会增加,同时文件计数和名称会并行显示。
还有另一个操作,如果用户点击暂停,它(线程)必须暂停,直到用户点击恢复。
问题是,以上对于两个线程都不起作用(不会挂起和恢复)..但适用于单线程。
请检查代码以获得想法并回复我可以做什么!
在按钮上单击开始
void CThreadingEx3Dlg::OnBnClickedStart()
{
m_ProgressBar.SetRange(start,end);
myThread1 = AfxBeginThread((AFX_THREADPROC)MyThreadFunction1,this);
myThread2 = AfxBeginThread((AFX_THREADPROC)MyThreadFunction2,this);
}
线程1
UINT MyThreadFunction1(LPARAM lparam)
{
CThreadingEx3Dlg* pthis = (CThreadingEx3Dlg*)lparam;
for(int intvalue =pthis->start;intvalue<=pthis->end; ++intvalue)
{
pthis->SendMessage(WM_MY_THREAD_MESSAGE1,intvalue);
}
return 0;
}
线程1函数
LRESULT CThreadingEx3Dlg::OnThreadMessage1(WPARAM wparam,LPARAM lparam)
{
int nProgress= (int)wparam;
m_ProgressBar.SetPos(nProgress);
CString strStatus;
strStatus.Format(L"Thread1:Processing item: %d", nProgress);
m_Static.SetWindowText(strStatus);
Sleep(100);
return 0;
}
线程2
UINT MyThreadFunction2(LPARAM lparam)
{
CThreadingEx3Dlg* pthis = (CThreadingEx3Dlg*)lparam;
for(int i =pthis->start;i<=pthis->end;i++)
{
pthis->SendMessage(WM_MY_THREAD_MESSAGE2,i);
}
return 0;
}
线程2函数
LRESULT CThreadingEx3Dlg::OnThreadMessage2(WPARAM wparam,LPARAM lparam)
{
m_Static1.GetDlgItem(IDC_STATIC6);
m_Static1.SetWindowTextW(L"Thread2 Running");
Sleep(100);
m_Static1.SetWindowTextW(L"");
Sleep(100);
return TRUE;
}
void CThreadingEx3Dlg::OnBnClickedPause()
{
// TODO: Add your control notification handler code here
if(!m_Track)
{
m_Track = TRUE;
GetDlgItem(IDCANCEL)->SetWindowTextW(L"Resume");
myThread1->SuspendThread();
WaitForSingleObject(myThread1->m_hThread,INFINITE);
myThread2->SuspendThread();
m_Static.SetWindowTextW(L"Paused..");
}
else
{
m_Track = FALSE;
GetDlgItem(IDCANCEL)->SetWindowTextW(L"Pause");
myThread1->ResumeThread();
myThread2->ResumeThread();
/*myEventHandler.SetEvent();
WaitForSingleObject(myThread1->m_hThread,INFINITE);*/
}
}
最佳答案
我想我应该将评论中的一些讨论总结成一个答案。
在 Windows 编程中,您永远不应该尝试从后台线程操作 GUI 控件,因为这样做会导致您的程序死锁。这意味着只有主线程应该接触 GUI 的元素。 (从技术上讲,重要的是哪个线程创建了控件,但在后台线程中创建控件并不常见)。
此要求在 Joe Newcomer's article on worker threads 中有详细说明(请参阅“工作线程和 GUI II:不要触摸 GUI”)。
您正在使用 SendMessage
在你的线程程序中。这会导致调用目标控件的适当消息处理程序,但在调用 SendMessage
的线程中。 .在您的情况下,这意味着后台线程运行消息处理程序,因此更新进度条和标签。
另一种方法是使用 PostMessage
.这会导致消息被添加到队列中以由主线程的消息循环处理。当主线程开始运行时,它会按照消息添加到队列中的顺序处理消息,并调用消息处理程序本身。由于主线程拥有窗口,因此更新控件是安全的。
您还应该注意 SuspendThread
和 ResumeThread
很难做到正确。您可能想阅读 this section Joe Newcomer 的文章,其中描述了一些危险。
使用 timer 通常可以更好地完成此类任务。 .这是一种让操作系统在特定时间过去后通知您的程序的机制。您可以使用如下计时器来实现它:
BEGIN_MESSAGE_MAP(CThreadingEx3Dlg, CDialog)
ON_WM_DESTROY()
ON_WM_TIMER()
END_MESSAGE_MAP()
void CThreadingEx3Dlg::OnTimer(UINT_PTR nTimerID)
{
static int progress = 0;
if (nTimerID == 1)
{
m_ProgressBar.SetPos(progress);
CString strStatus;
strStatus.Format(_T("Processing item: %d"), progress);
m_Static.SetWindowText(strStatus);
progress++;
if (progress > end) // If we've reached the end of the updates.
KillTimer(1);
}
}
BOOL CThreadingEx3Dlg::OnInitDialog()
{
// ... initialize controls, etc, as necessary.
SetTimer(1, 100, 0);
}
void CThreadingEx3Dlg::OnDestroy()
{
KillTimer(1);
}
如果您希望同时处理两个更新,它们可以使用相同的计时器。如果它们需要在不同的时间发生(例如一个间隔为 100 毫秒,另一个间隔为 150 毫秒),那么您可以调用
SetTimer
两次使用不同的ID。要暂停操作,请调用 KillTimer
.要恢复它,请调用 SetTimer
再次。
关于multithreading - 在 MFC 中同时挂起 2 个线程的问题!,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2736749/