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

本文围绕VC++开发中线程同步问题展开。作者在主应用程序点击“查找”按钮时,因查找文件事件导致界面重绘慢、CPU占用高,于是为该事件启动新线程。同时介绍了Ybbozman解决主线程等待第二个线程终止问题的方法,包括两个函数及示例代码,还提及相关API函数。

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

来自 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(荷兰著名计算机科学家Dijkstra将进程或线程的同步问题抽象为信号态,顺便愐怀一下Dijkstra,他已于2002年8月6号在荷兰去逝)的一个线程之间的同步函数,当主线程T所等待的线程T2信号态到达时(利用特定的消息-message指示信号态的到达),将返回WAIT_OBJECT_0,::MsgWaitForMultipleObjects的最后一个参数QS_ALLINPUT指定了所有输入消息类型都可作为信号态到达并因此返回,PeekMessageLoop()将消息队列中的所有消息标志为旧消息,因此::MsgWaitForMultipleObjects并不返回,最后,只有当线程T2结束后返回WAIT_OBJECT_0.

 

关于等待多个线程同步的问题,参考::MsgWaitForMultipleObjects函数用法。

 

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

### Linux 中主线程与子线程的区别及用法 #### 一、主线程与子线程的概念区别 在 Linux 系统中,主线程通常是指程序启动时创建的第一个线程。它是整个进程的入口点,并负责初始化其他资源和线程。子线程则是由主线程或其他线程通过 `pthread_create` 函数创建的新线程[^1]。 - **生命周期独立性** 主线程与子线程可以具有不同的生命周期模式。一种常见的场景是两者互不干扰,即使主线程结束,子线程仍可继续运行;一种情况是当主线程结束后,所有未完成的子线程也会随之终止。 - **资源共享特性** 所有的线程(包括主线程和子线程)都共享同一进程地址空间内的资源,例如文件描述符、内存映射区域以及全局变量等。然而,每个线程拥有自己的栈空间和寄存器状态[^3]。 #### 二、Pthreads API 创建与管理线程的方法 以下是使用 POSIX Threads (`pthreads`) 库来管理和操作主线程与子线程的一些基本方法: ##### 1. 创建新线程 要创建一个新的子线程,需调用 `pthread_create()` 函数: ```c #include <pthread.h> int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg); ``` 其中参数说明如下: - `thread`: 返回生成的新线程 ID; - `attr`: 设置线程属性,默认传入 NULL 表示采用默认配置; - `start_routine`: 新线程执行的目标函数指针; - `arg`: 向目标函数传递的数据指针。 注意,在某些情况下快速终止的分离线程可能导致错误获取其实际 ID[^2]。 ##### 2. 控制线程退出方式 对于希望优雅地关闭某条线程的情形下,可通过调整取消行为实现更灵活的操作。具体来说有两种主要类型——延迟取消(`PTHREAD_CANCEL_DEFERRED`) 和即时取消(`PTHREAD_CANCEL_ASYNCHRONOUS`) [^4]: - 延迟取消意味着只有在线程到达特定取消点时才会真正停止工作流程。 - 即时取消允许随时强制中断当前活动中的任何计算过程。 ##### 3. 发送信号至单个或全体成员 利用标准 C 提供的功能或者专门针对多线程环境设计接口均可达成向某个单独实体或者是整体组群传达消息的目的。比如借助于系统级命令 kill() 或者专用工具 pthread_kill()[^3]: ```c // 给定 pid 对应的整体实例投递通知 if(kill(getpid(), SIGUSR1)==0){ printf("Signal sent successfully.\n"); } // 针对指定 tid 实施精准打击 pthread_kill(thread_id,SIGTERM); ``` 外值得注意的是关于条件变量同步机制方面存在局限性:假如没有任何监听方处于待命姿态接收到来自生产者的提示信息的话那么这些更新将会被完全丢弃掉而不会保留下来供后续使用者发现[5]. #### 总结 综上所述,Linux 下面围绕着主次角色之间存在着多样化的协作形式可供开发者依据实际需求选取最合适的解决方案.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值