【线程】监听主程序执行完成时,子线程立即启动

本文介绍了一种在主程序执行完成后立即启动子线程的方法,通过监听线程状态,确保主业务完成后再调用子线程逻辑,适用于需要在事务提交后执行额外任务的场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

在开发过程中,各位是否有遇到一下场景。
当前方法(主方法)执行完成之后,需要调用其他系统接口、new一个新线程执行其他业务、调用第三方系统api。
但此时因为“主方法”未提交事务,其他接口系统、线程 无法拿到数据

1、思路

有没有办法判断当前线程执行完成之后,再次发起调用子业务处理?
1、有的,获取当前线程,
2、通过循环,获取线程状态,当 线程状态=TERMINATED”的时候,说明主方法已经结算,这时就可以继续当前子业务的进行

2、实现

2.1、获取线程

// 利用 Thread.currentThread() 获取当前状态
Thread thread = Thread.currentThread();

2.2、工具类

@Slf4j
public class ThreadUtils {

    /**
     * 监听指定线程是否已经执行完毕或者销毁
     * @param waitNum 监听次数
     * @param sleepTime 每次监听间隔时长
     * @param thread 监听的线程
     */
    public static void threadWait(int waitNum, long sleepTime, Thread thread) {

        for (int i = 0; i < waitNum; i++) {
            try {
                Thread.sleep(sleepTime);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            State state = thread.getState();
            if ("WAITING".equals(state.name()) ||  "TERMINATED".equals(state.name())) {
                log.info("程序已完成【{}】:{}",i+1, state);
                return;
            } else {
                log.debug("等待【{}】:{}",i+1, state);
            }
        }
    }

}

2.3、实战

  public static void main(String[] args) {
        Thread thread = Thread.currentThread();
        new Thread(()->{
            ThreadUtils.threadWait(20,200,thread);
            log.info("主线程已经结算");
        }).start();
        try {
            // 模拟接口处理中
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("我是主线程:已经执行完成");
    }


2.3、效果

在这里插入图片描述

3、总结

通过监听线程的状态判断主业务是否完成,然后调用子线程的逻辑,并且是两段独立代码,双方互不影响

<think>好的,我现在需要帮助用户解决在MFC子线程中更新CString的问题。首先,用户之前已经询问过关于std::atomic和CString的结合使用,现在进一步关注如何在子线程中安全地更新CString。我需要回顾之前的回答,确保这次的内容不重复,并且更具体地针对MFC的环境。 用户可能正在开发一个多线程的MFC应用程序,子线程需要更新界面显示的字符串,比如进度信息或状态。这候直接在线程中操作CString可能会导致竞争条件或界面卡顿,因为MFC的控件通常只能在主线程中更新。所以,用户需要了解如何安全地在子线程中修改CString,并通知主线程更新UI。 首先,我需要考虑MFC的线程模型。MFC的窗口对象和控件不是线程安全的,所有UI操作都必须在主线程(通常是创建窗口的线程执行。因此,子线程不能直接更新UI控件中的CString,而是需要通过某种机制将数据传递给主线程处理。 接下来,我需要列举几种常见的解决方法。之前提到过互斥锁、原子指针和shared_ptr,但MFC可能更常用的是窗口消息或者自定义消息。例如,子线程发送消息给主线程主线程接收到消息后更新CString并刷新界面。这种方法避免了直接跨线程操作UI的问题。 另外,使用CEvent类或者临界区(CCriticalSection)来同步对CString的访问也是一个可能的方案。子线程在修改共享的CString前锁定临界区,修改完成后解锁,确保主线程在读取也进行同步。这种方法适用于需要在多个线程间频繁读写的情况,但需要注意死锁的问题。 还需要考虑用户是否使用C++11或更高版本,因为之前的回答提到了std::mutex和std::atomic,但在MFC中可能更倾向于使用MFC自带的同步类,比如CSyncObject及其派生类。同,PostMessage和SendMessage是MFC中跨线程通信的常用手段,特别是PostMessage更适合异步操作,避免阻塞子线程。 另外,用户可能需要示例代码,所以需要提供使用PostMessage传递字符串的示例,或者使用临界区保护CString的代码片段。需要注意的是,当传递CString对象本身,必须确保其生命周期的安全,避免悬垂指针或内存泄漏。例如,在消息参数中传递字符串的拷贝,或者使用全局/成员变量配合同步机制。 还需要提醒用户,直接在线程间传递CString对象指针可能会有风险,特别是如果子线程在发送消息后继续修改该字符串,而主线程尚未处理消息,这候可能导致数据不一致。因此,建议在消息处理传递字符串的副本,或者使用线程安全的容器来管理数据。 另外,可能还需要提到使用AfxBeginThread创建线程的注意事项,确保线程安全,以及在线程结束正确清理资源。例如,在子线程结束发送消息通知主线程更新状态,或者使用事件对象来通知主线程数据已准备好。 最后,总结各个方法的优缺点,帮助用户根据具体场景选择最合适的方案。例如,如果更新频率低,使用PostMessage更简单;如果频繁更新,可能需要临界区或事件对象来保证性能和数据一致性。</think>在 MFC 中,子线程直接操作 UI 控件或更新与 UI 关联的 `CString` 是**线程不安全**的(因为 MFC 的窗口对象只能在创建它们的线程中访问)。以下是安全实现子线程更新 `CString` 并通知主线程刷新 UI 的几种方法: --- ### **方法 1:通过消息机制传递字符串** 利用 `PostMessage` 或 `SendMessage` 将子线程中的 `CString` 传递给主线程处理,确保线程安全。 #### **步骤示例**: 1. **定义自定义消息**(通常在头文件中): ```cpp #define WM_UPDATE_STRING (WM_USER + 1) ``` 2. **在主窗口类中添加消息处理函数**: ```cpp // 头文件声明 afx_msg LRESULT OnUpdateString(WPARAM wParam, LPARAM lParam); // CPP 文件消息映射 BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) ON_MESSAGE(WM_UPDATE_STRING, OnUpdateString) END_MESSAGE_MAP() ``` 3. **子线程发送消息传递字符串**: ```cpp // 子线程函数 UINT WorkerThread(LPVOID pParam) { CString strNew = _T("子线程更新的内容"); // 通过消息传递字符串(需确保主窗口句柄有效) ::PostMessage( (HWND)pParam, // 主窗口句柄 WM_UPDATE_STRING, // 自定义消息 (WPARAM)new CString(strNew), // 传递堆上的 CString 对象指针 0 ); return 0; } ``` 4. **主线程处理消息并更新 UI**: ```cpp LRESULT CMainFrame::OnUpdateString(WPARAM wParam, LPARAM lParam) { CString* pStr = (CString*)wParam; // 更新 UI(例如设置到编辑框) m_editCtrl.SetWindowText(*pStr); // 释放堆内存 delete pStr; return 0; } ``` --- ### **方法 2:使用同步类保护共享 CString** 通过 `CCriticalSection` 或 `CMutex` 保护共享的 `CString` 对象,确保读写操作的原子性。 #### **示例代码**: ```cpp // 全局或成员变量 CCriticalSection g_cs; CString g_sharedString; // 子线程修改字符串 UINT WorkerThread(LPVOID pParam) { CSingleLock lock(&g_cs, TRUE); // 加锁 g_sharedString = _T("子线程更新的内容"); lock.Unlock(); // 解锁(析构自动释放) // 通知主线程刷新(可选) ::PostMessage((HWND)pParam, WM_UPDATE_UI, 0, 0); return 0; } // 主线程读取字符串 void CMainFrame::OnUpdateUI() { CSingleLock lock(&g_cs, TRUE); m_editCtrl.SetWindowText(g_sharedString); } ``` --- ### **方法 3:使用事件(CEvent)触发更新** 结合 `CEvent` 和共享变量,实现线程间同步。 #### **示例代码**: ```cpp // 全局或成员变量 CEvent g_event; // 事件对象 CString g_sharedString; // 共享字符串 CCriticalSection g_cs; // 保护共享字符串 // 子线程逻辑 UINT WorkerThread(LPVOID pParam) { { CSingleLock lock(&g_cs, TRUE); g_sharedString = _T("子线程更新的内容"); } g_event.SetEvent(); // 触发事件 return 0; } // 主线程监听事件(例如在 OnIdle 或定器中) BOOL CMainFrame::OnIdle(LONG lCount) { if (g_event.Lock(0)) { // 非阻塞检查事件 CSingleLock lock(&g_cs, TRUE); m_editCtrl.SetWindowText(g_sharedString); g_event.ResetEvent(); } return CFrameWnd::OnIdle(lCount); } ``` --- ### **注意事项** 1. **避免直接跨线程操作 UI** MFC 控件(如 `CEdit`、`CStatic`)必须由主线程更新,子线程只能通过消息或同步机制间接操作。 2. **字符串生命周期管理** 使用 `PostMessage` 传递 `CString*` ,需在主线程中手动释放内存,防止内存泄漏。 3. **性能优化** 高频更新场景下,频繁的 `PostMessage` 可能导致消息队列拥堵。可合并更新或使用双缓冲机制。 --- ### **总结** | 方法 | 适用场景 | 优点 | 缺点 | |--------------|--------------------------|---------------------------|--------------------------| | 消息机制 | 低频更新,简单逻辑 | 代码清晰,直接绑定 UI 更新 | 内存管理需谨慎 | | 同步类 | 高频读写,共享数据 | 灵活控制临界区 | 需手动处理锁的粒度 | | 事件触发 | 异步通知,定刷新 | 减少消息队列压力 | 需结合其他同步机制 | 根据实际需求选择最合适的方式,优先使用 **消息机制** 实现 UI 更新,复杂数据共享场景则选择 **同步类 + 事件**。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值