与MFC中的WaitForSingleObject和CEvent进行线程协调

时间:2014-07-25 09:03:15

标签: mfc

在我的一个MFC应用程序中,有几个工作线程。这些主题的性质如下:

  1. 大多数线程执行一次任务并等待条件成立,以便进一步执行。
  2. 在少数情况下,线程会无限期地等待,直到条件变为真,而在其他情况下,它会等待某些时间段,并且根据条件变为真或时间段的到期,以较早者为准,它需要一些动作并再次开始等待。

  3. 线程必须在应用程序的整个生命周期中运行,但不一定每时每刻都在运行。

  4. 目前每个线程都有一个无限循环,它执行它的任务;因为每个线程必须在整个应用程序的生命周期中工作,所以我不想每次都关闭这些线程并重新创建。在循环内部,我使用了WaitForSingleObject和一个自动重置CEvent进行这种线程协调。 CEvent对象从任何线程或UI线程发出信号。

    在此上下文中,我有以下查询:

    我。这种方法是否符合我的要求?

    II。为此目的使用如此多的CEvent对象是否有任何重大开销。 还有更好的选择吗?

    III。在某些情况下,线程无限地等待CEvent对象发出信号,并且只有在从另一个线程收到消息后才从windows消息处理程序发出信号。该消息通过PostMessage接收。在这里,我担心丢失从线程发送的消息。如果Message处理程序跳过消息,则它无法声明CEvent对象,并且等待的线程必须无限期等待。必须采取哪些预防措施来避免这种情况?有没有更好的方法来重建计划?

    请给我一些更好的选择。

3 个答案:

答案 0 :(得分:0)

使用WaitForMultipleObjects而不是WaitForSingleObject。每个事件数组中的第一个事件应该是一个设置为关闭应用程序的全局CEvent。每个线程都检测到这个事件,并通过从线程函数返回来干净地退出。

设置关闭事件(通常在OnClose中)后,在线程句柄上使用WaitForMultipleObjects等待所有辅助线程关闭。这可以确保线程可以访问的任何全局数据都会保留,直到线程消失为止。

答案 1 :(得分:0)

你的方法很好。不要担心多个CEvent对象。在您的情况下,每个线程必须至少有一个事件。

我不确定您使用什么方法退出线程。但是您可能需要额外的CEvent对象来检测是否必须正常退出线程。

所以在这种情况下你会在每个线程中使用WaitForMultipleObjects(1个事件是否运行,另一个事件是退出线程)。

如果线程太多,我建议您在需要时生成子线程。子线程只运行一次并退出。在父线程中,您将再次等待查看必须运行哪个子线程。您可以根据事件对象数组检测要生成的线程。这种方法将占用较少的系统资源。

答案 2 :(得分:0)

在我的应用程序中,我只使用10到12个工作线程。我读到了某个地方 当一个线程调用一个等待函数时,它从用户模式进入内核模式。它有点贵,因为进入内核模式,需要大约1000个处理器周期,这在具体情况下可能过于昂贵。

然而,正如哥特和ScottMcP建议的那样,我在以下方式中使用WaitForMultipleObjects而不是WaitForSingleObject来确保在清理线程使用的任何资源之前正常关闭线程。

CEvent doWork,exitThread; //Auto reset events
CWinThread* MyThread;
UINT MyThreadFunction(LPVOID param);

BOOL CMyDlg::OnInitDialog()
{
    //Other initialization code
    MyThread=AfxBeginThread(MyThreadFunction, CMyDlg::GetSafeHwnd());
    //Any other initialization code
    return TRUE;
}

UINT MyThreadFunction(LPVOID param) 
{
HANDLE waitEvents[2];
waitEvents[0]=doWork;
waitEvents[1]=exitThread;
while(true)
{

  DWORD stat=::WaitForMultipleObjects(2, waitEvents, FALSE, INFINITE);
  switch(stat)
  {
    case WAIT_OBJECT_0 + 0:
        // doWork CEvent is signalled; proceed to do some work
    break;

    case WAIT_OBJECT_0 + 1:
        //exitThread is signalled; so exit from this thread handler function
    return 0;

    case WAIT_FAILED:
        // failure may be related to wrong handles passed for lpHandles 
    break;

    case WAIT_TIMEOUT:
        // not applicable here because dwMilliseconds parameter is set to INFINITE
    break;
  }
}
return 0;
}

CMyDlg::OnClose()
{
  exitThread.SetEvent();
  DWORD Stat=WaitForSingleObject(MyThread->m_hThread, INFINITE);   
  if(Stat==WAIT_OBJECT_0)
  {
    //Thread supposed to be Exited
    //Cleanup allocated resources here
  }
  else if(Stat==WAIT_TIMEOUT)
  {
    //not applicable here
  }
  else if(Stat==WAIT_FAILED)
  {
    //Invalid thred handle passed or something else
  }
  EndDialog(0);
} 

如果发现任何错误或有任何改进的余地,请对我的回答发表评论。