You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

事件触发时停止线程的实现问题及mutex抢占解决方案

解决线程终止与互斥锁竞争的问题

咱们先捋清楚你当前代码的核心问题:你的子线程在每次迭代解锁后,立刻又进入下一次循环的lock()操作,主线程在sleep 1ms后尝试获取锁的时候,几乎每次都抢不过子线程——子线程解锁后马上就重新加锁了,主线程根本没机会拿到锁去修改stop变量,直到子线程跑完10次循环才释放锁,这时候修改stop已经完全没用了。

下面给你两个针对性的解决方案:

方案1:用std::condition_variable实现优雅的线程终止

我们可以用条件变量来让子线程在等待主线程信号的间隙释放锁,这样主线程能轻松拿到锁并发送停止信号。另外注意别用volatile,C++里线程间的内存可见性得靠同步原语(比如mutex、condition_variable)来保证,volatile根本不适合这个场景。

修改后的代码如下:

#include <thread>
#include <mutex>
#include <iostream>
#include <chrono>
#include <condition_variable>
using namespace std;

void function_(bool& stop, mutex& mtx, condition_variable& cv) {
    unique_lock<mutex> lock(mtx);
    for (int i = 0; i < 10; i++) {
        // 先检查是否要停止
        if (stop) {
            return;
        }
        // 解锁去执行任务,别一直占着锁
        lock.unlock();
        //doSomething();
        this_thread::sleep_for(chrono::milliseconds(1));
        cout << "Iteration " << i << endl;
        // 重新加锁,准备下一次检查或等待
        lock.lock();
        // 等待主线程的信号,最多等1ms(也可以无限等,看你的需求)
        cv.wait_for(lock, chrono::milliseconds(1));
    }
}

int main() {
    bool stop = false;
    mutex mtx;
    condition_variable cv;
    thread functionThread(function_, ref(stop), ref(mtx), ref(cv));
    
    this_thread::sleep_for(chrono::milliseconds(1));
    
    {
        lock_guard<mutex> lock(mtx);
        stop = true;
    }
    // 发送信号唤醒子线程,让它立刻检查停止条件
    cv.notify_one();
    
    cout << "Changed boolean variable value" << endl;
    functionThread.join();
    system("pause");
    return 0;
}

关键改动说明:

  • 用std::unique_lock代替直接调用lock()/unlock(),它能更灵活地控制锁的释放和重获取
  • 子线程在执行任务(sleep或doSomething)前先解锁,避免一直占用锁,给主线程留足修改stop的机会
  • 用condition_variable::wait_for让子线程在等待时自动释放锁,主线程可以随时发送信号唤醒它检查停止条件
  • 主线程修改stop后,调用notify_one()唤醒子线程,确保它立刻响应停止信号

这样运行后,子线程只会执行1-2次迭代就会停止,完全符合你的预期。

方案2:处理doSomething()耗时较长的情况

如果doSomething()执行时间很长,而且你不能修改它的内部代码,那没有安全的跨平台方法可以强制终止线程——C++标准根本不支持强制终止线程,因为这会导致线程持有的资源(比如mutex、内存)无法正确释放,引发各种未定义行为(程序崩溃、资源泄漏等)。

那我们能做的最优选择是:

  • 在子线程调用doSomething()前先检查stop标志,如果已经要停止就直接返回;如果已经进入doSomething()执行,那只能等它执行完再检查停止条件。修改后的子线程代码大概是这样:
void function_(bool& stop, mutex& mtx, condition_variable& cv) {
    unique_lock<mutex> lock(mtx);
    for (int i = 0; i < 10; i++) {
        if (stop) {
            return;
        }
        lock.unlock();
        
        // 调用耗时函数前再检查一次,避免白跑
        if (stop) {
            lock.lock();
            return;
        }
        doSomething(); // 耗时很长的函数
        
        cout << "Iteration " << i << endl;
        lock.lock();
        cv.wait_for(lock, chrono::milliseconds(1));
    }
}

这样如果主线程在子线程调用doSomething()前发送了停止信号,子线程就不会进入这个耗时函数;但如果已经进入了,那只能等它执行完。

如果你真的非要强制终止(完全不考虑安全风险),可以用平台相关的API,比如Windows下的TerminateThread,Linux下的pthread_cancel,但这些方法都是极其不安全的,大概率会搞崩你的程序,非常不推荐使用。

内容的提问来源于stack exchange,提问作者Aral

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 03:57:25