如何暂停主线程直到第二个线程的终止?

原创 2004年09月04日 16:34:00

如何暂停主线程直到第二个线程的终止?<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

来自 http://www.codeproject.com/threads/waitthreadmsi.asp#xx441032xx

By Ybbozman

不要被线程这个词给吓坏了,留下来先看看吧;)

作为翻译这篇短文的我在VC++开发中遇到了与 Ybbozman 相类似的问题,在主应用程序中(主进程-其实还是线程,称主线程也可),点击“查找”按钮时,我作了一个搜索的递归查找文件的事件-这个事件将非常慢,结果是导致界面重绘明显变慢、cpu资源占用率非常高,原因是windows抢先式多任务将此主线程的优先级置为最高,查找文件事件是作为这个主线程正在执行的事件,cpu大部分的时间片会交给查找文件事件,而界面重绘的操作速率将变得不可预知。

为这个查找文件事件启动一个新的工作线程,是非常高效的,查找文件事件在新的工作线程中工作,但优先级是不会高于当前主线程的,这就保证了界面重绘操作的正常进行,问题是我想在查找文件事件完成后再继续执行主线程的某些操作,这就涉及到线程之间等待-wait(称之为同步-Synchronization更好些)的问题,Ybbozman 的问题与我这个问题有些类似,下面看一下Ybbozman 是如何解决线程之间等待的问题。

简介

 

几周前,我需要制作一个对话框将它作为MSI安装程序(Windows2000的软件安装)的一部分,为此所写的代码必须是作为一个Regular(规则)DLL发布。这个对话框是否可见,完全依赖于安装完成的结果,即该功能依赖于另一个线程(在这里是正在进行的安装过程的工作线程)完成,安装完成后这个线程被终止,并最终显示这个对话框。

 

解决

 

你必须写两个函数,第一个void CMyTestDialog::PeekMessageLoop() 将从消息队列中获取消息:

void CMyTestDialog::PeekMessageLoop()

{

    MSG msg;

    while (PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE))

    {

        TranslateMessage(&msg);

        DispatchMessage(&msg);

    }

}

第二个, void CMyTestDialog::WaitForThreadToTerminate(HANDLE hThread) 将指示哪个线程需要等待并作进一步处理:

void CMyTestDialog::WaitForThreadToTerminate(HANDLE hThread)

{

    DWORD dwRet;

    do

    {

        dwRet = ::MsgWaitForMultipleObjects(1, &hThread, FALSE,

            INFINITE, QS_ALLINPUT);

        if (dwRet != WAIT_OBJECT_0)

        {

            PeekMessageLoop();

        }

    } while ((dwRet != WAIT_OBJECT_0) && (dwRet != WAIT_FAILED));

}

示例代码

假设对话框上有一个按钮,当点击按钮时,开始启动第二个线程,等到第二个线程完成后,我们再往下继续主线程:

void CMyTestDialog::OnButton1()

{

    m_pUpdateThread = AfxBeginThread(UpdateDeviceContent,

        (LPVOID)this/*, THREAD_PRIORITY_BELOW_NORMAL*/);

    if (m_pUpdateThread)

    {

        WaitForThreadToTerminate(m_pUpdateThread->m_hThread);

    }

//Do whatever you want after the action is finished

}

 

 

Ybbozman 在解决这个问题时用到了线程之间同步的API函数::MsgWaitForMultipleObjects 函数,它是用于等待某个对象(在这里是要等待的线程T2)的信号态-Semaphore(注1)同步函数,当主线程T所等待的线程T2信号态到达时(利用特定的消息-message指示信号态的到达,将返回WAIT_OBJECT_0,::MsgWaitForMultipleObjects的最后一个参数QS_ALLINPUT指定了所有输入消息类型都可作为信号态到达并因此返回,PeekMessageLoop()将当前运行线程中的任何一个窗口消息以及由PostThreadMessage递交到当前运行线程中的所有消息从消息队列中移除,因此,迭代再次调用::MsgWaitForMultipleObjects时,只有新的消息到达后该函数才返回;此外,PeekMessageLoop()调用后,迭代再次调用::MsgWaitForMultipleObjects之前,会处理一些系统事件:例如,有关窗体重绘的WM_PAINT消息(注意:即使PeekMessage最后一个参数设为PM_REMOVEPeekMessageLoop()调用后,WM_PAINT消息也不会从消息队列中移除)。

讲了许多,我都有点晕了,再归纳一下:

一. ::MsgWaitForMultipleObjects迭代等待指定线程中的特定消息,当线程结束时,::MsgWaitForMultipleObjects将返回WAIT_OBJECT_0以表示线程的结束!

二. PeekMessageLoop迭代获得当前运行线程中的任何一个窗口消息以及由PostThreadMessage递交到当前运行线程中的消息,调用PeekMessageLoop后将消息从消息队列中移除, 其目的有两个:

a. 再次调用::MsgWaitForMultipleObjects时必须等到一个新的消息到达后才返回;
b. 更新系统事件,这是很有用的功能,这将防止在消息等待过程中(即迭代::MsgWaitForMultipleObjects)独占CPU资源,而不处理某些重要的系统事件:诸如:硬件输入消息,窗口重绘,定时消息等等。



MsgWaitForMultipleObjects支持下面对象的同步:

Mutex 互斥 Event 事件 Semaphore 信号 Process 进程 Thread 线程 Critical section 临界段

此外,线程之间的同步函数还有WaitForSingleObject, WaitForMultipleObjects,使用方法大同小异,它们除了不支持Critical section(临界段)。而MsgWaitForMultipleObjects更多地用于等待来自于同步对象中某些特殊的消息。

最后,文中错误难免,请有识之士批评指正。



注1:荷兰著名计算机科学家Dijkstra将进程或线程的同步问题抽象为信号态,Dijkstra已于2002年8月6号在荷兰去逝。


参考:MSDN帮助文档。

怎样让多个并发的线程暂停,然后在主线程中改变标记让它们继续运行

本人刚刚对多线程进行初步学习,对多线程只是初步的了解。因为在写代码的时候遇到的了这个问题,所以就拿来说说。 两种比较笨的解决方法。 一种是在子线程中用一个while循环判断 public voi...
  • tj7788
  • tj7788
  • 2013-07-25 16:17:41
  • 711

如何暂停主线程直到第二个线程的终止?

如何暂停主线程直到第二个线程的终止?来自 http://www.codeproject.com/threads/waitthreadmsi.asp#xx441032xxBy Ybbozman 不要被线...
  • yjgx007
  • yjgx007
  • 2004-09-04 16:34:00
  • 8115

线程暂停和继续实现

开启一个子线程来显示发动机上的运行时间,如果发动机暂停运行,那么这个线程也会暂停,发动机又开动的时候,线程继续开启,数据也是连贯着的; Timer timer=new Timer();T...
  • u014492513
  • u014492513
  • 2017-02-24 09:38:54
  • 817

如何用通过C++11提供的std::condition_variable实现主线程控制子线程的启动和停止

讲述了如何使用C++ 11的条件变量实现主线程控制子线程任务的开始和停止,减少了启动线程的开销...
  • liyanjieliyanjie
  • liyanjieliyanjie
  • 2017-07-09 12:23:31
  • 531

C++实现的可以安全的暂停、继续、停止线程的封装类

在使用线程时,最麻烦的就是线程的同步控制,如暂停、继续、停止(包括暂停状态下)等。虽然微软提供了 SuspendThread、TerminateThread 等函数“似乎”可以完成这个功能,但如果你在...
  • fishjam
  • fishjam
  • 2012-04-04 16:15:39
  • 5132

<em>线程暂停</em>和线程继续,以及线程结束后发送自定义消息更新状态

WaitForSingleObject(thread,INFINITE);确实实现了,但是问题也来了:<em>主线程</em>里的计时...C#内存释放-线程控制-线程启动-<em>线程暂停</em> 立即下载 上传者: hubins 时间: 2014...
  • 2018年04月08日 00:00

Android线程操作类(暂停、重新开启、停止)

场景:  在程序中如果需要在后台长时间做一件事情,比如联网获取数据等操作,就要用到线程。  但为了提高用户体验,有以下几点需要注意:  1、程序可见时线程开始运行;  2、程序不可见时线程暂停...
  • luoyouren
  • luoyouren
  • 2016-08-05 10:42:06
  • 2790

如何正确停止java中的线程

为什么不能使用Thread.stop()方法? 从SUN的官方文档可以得知,调用Thread.stop()方法是不安全的,这是因为当调用Thread.stop()方法时,会发生下面两件事: 1. ...
  • liranke
  • liranke
  • 2012-12-07 18:20:31
  • 18443

C++实现的可以安全的暂停、继续、停止线程的线程类和Sample

  • 2012年04月04日 16:11
  • 46KB
  • 下载

android 停止 终止 Thread 线程的三种方法

有三种方法可以使终止线程。     1.  使用退出标志,使线程正常退出,也就是当run方法完成后线程终止。     2.  使用stop方法强行终止线程(这个方法不推荐使用,因为stop...
  • a2241076850
  • a2241076850
  • 2016-10-19 11:53:40
  • 15743
收藏助手
不良信息举报
您举报文章:如何暂停主线程直到第二个线程的终止?
举报原因:
原因补充:

(最多只允许输入30个字)