在MFC中同时挂起2个线程的问题!

时间:2010-04-29 11:07:43

标签: multithreading mfc

我正在学习线程和多线程。所以我刚刚创建了一个小应用程序,我将在其中进行更新 进度条和静态文本使用线程。我从用户获得两个输入,开始和结束值 循环应旋转多长时间。我的应用程序中有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;
}

thread1函数

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;
}

thread2

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;
}

thread2函数

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);*/
    }
}

3 个答案:

答案 0 :(得分:4)

我认为我应该将评论中的一些讨论总结为一个答案。

在Windows编程中,您永远不应该尝试从后台线程操作GUI控件,因为这样做会导致程序死锁。这意味着只有主线程才能触及GUI的元素。 (从技术上讲,重要的是哪个线程创建了控件,但在后台线程中创建控件并不常见。)

此要求详见Joe Newcomer's article on worker threads(请参阅“工作线程和GUI II:不要触摸GUI”)。

您在线程程序中使用SendMessage。这会导致调用目标控件的相应消息处理程序,但调用SendMessage 的线程中的。在您的情况下,这意味着后台线程运行消息处理程序,因此更新进度条和标签。

另一种方法是使用PostMessage。这会将消息添加到队列中,以便由主线程的消息循环处理。当主线程运行时,它按照它们添加到队列的顺序处理消息,调用消息处理程序本身。由于主线程拥有窗口,因此更新控件是安全的。

您还应该注意SuspendThreadResumeThread很难做到。您可能想阅读Joe Newcomer的文章this section,该文章描述了一些危险。


使用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毫秒),那么您可以使用不同的ID呼叫SetTimer两次。要暂停操作,请致电KillTimer。要恢复此操作,请再次致电SetTimer

答案 1 :(得分:1)

多线程和消息排队是一个非常复杂的游戏。当您将ThreadMessage从ThreadA发送到同一个线程时,它只是调用消息处理程序。如果从ThreadA到另一个线程(ThreadB),那么它会变得更复杂。然后,ThreadA将消息发送到ThreadB的消息队列,并等待一个信号,说明ThreadB已完成处理消息并发送了返回值。这引发了一个即时问题。如果ThreadB没有抽取消息,那么你就会遇到死锁,因为ThreadB中的消息永远不会被“分派”。这也引发了一个更大的问题。如果ThreadB的消息需要向ThreadA中创建的控件发送消息,那么您就会遇到大量的架构问题。由于ThreadA当前暂停等待ThreadB返回并且ThreadB被挂起,等待ThreadA返回。什么都不会发生......他们都会被暂停。

真的是这样的。只要你记住这些问题,它就很容易了。即尽管其他人所说的话,它绝对是可能的。

一般情况下,虽然你的线程是毫无意义的,因为你会立即向主线程发送一条消息来进行一些处理。为什么首先要打扰线程。你也可以不打扰,因为线程只会坐在那里等待主线程返回。

为什么在挂起第一个线程的时候“WaitForSingleObject”呢?为什么不暂停它们。

尽管如此,你并没有提供足够的信息来说明你正在做什么来说明发生了什么。单击暂停时会发生什么?例如?

答案 2 :(得分:0)

当多个线程与GUI交互时,Windows将无法正常运行。您需要重新组织您的程序,以免发生。