MFC中WaitForSingleObject和CEvent的线程协调

MFC中WaitForSingleObject和CEvent的线程协调,mfc,Mfc,在我的一个MFC应用程序中,有几个工作线程。这些螺纹的性质如下所示: 大多数线程只执行一次任务,然后等待条件为真,以便进一步执行。 在少数情况下,线程无限期地等待,直到条件变为真,在其他情况下,它等待特定的时间段,并基于条件变为真或时间段到期(以较早者为准),它采取一些操作并再次开始等待 线程必须在应用程序的整个生命周期中运行,但不一定每时每刻都在运行 目前,每个线程都有一个无限循环,它在其中执行自己的任务;由于每个线程都必须在应用程序的整个生命周期中工作,因此我不希望每次都关闭这些线程并重新创

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

大多数线程只执行一次任务,然后等待条件为真,以便进一步执行。 在少数情况下,线程无限期地等待,直到条件变为真,在其他情况下,它等待特定的时间段,并基于条件变为真或时间段到期(以较早者为准),它采取一些操作并再次开始等待

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

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

在这方面,我有以下疑问:

一,。该方法是否符合我的要求

二,。为此目的使用这么多CEvent对象是否有任何显著的开销。 还有更好的选择吗

iii.在某些情况下,线程无限期地等待发出CEvent对象的信号,并且该对象仅在从另一个线程接收消息后才从windows消息处理程序发出信号。该消息通过PostMessage接收。在这里,我担心的是丢失一个线程发送的消息。如果消息处理程序跳过一条消息,它将无法处理CEvent对象的状态,等待的线程必须无限等待。必须采取什么预防措施来避免这种情况?有没有更好的办法来重建这个计划


请给我推荐一些更好的选择。

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


通常在OnClose中设置关机事件后,使用线程句柄上的WaitForMultipleObjects等待所有辅助线程关闭。这样可以确保线程可能访问的所有全局数据都保持分配状态,直到线程消失。

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

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

因此,在本例中,您将在每个线程中使用WaitForMultipleObjects 1事件是否运行,另一个事件是否退出线程


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

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

然而,正如goths和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);
} 

如果检测到任何错误或有任何改进余地,请对我的回答进行评论。

我认为你的回答只解释了如何以干净的方式关闭应用程序。主线程可以确保所有工作线程都已成功退出;因此,现在是取消分配所有全局资源并退出的时候了。我使用一个布尔变量以不同的方式进行操作,但这不能确保在释放这些线程使用的全局数据之前正确关闭工作线程。虽然它非常清楚如何实施;你能给出一些实现这个想法的代码片段吗?你对我在帖子中提出的问题有什么建议吗?