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

主线程修改lightMode后如何立即终止子线程的循环?

解决方案

先明确原代码的核心问题:

  1. Work Handler不适合长时间循环:k_work的处理函数设计用于短周期任务,长时间阻塞会占用系统工作队列线程,影响其他任务执行,应该改用独立线程处理灯光控制逻辑。
  2. 无同步的共享变量访问:lightMode和pastLightMode被多线程读写,没有同步机制,会导致数据竞争和未定义行为。
  3. 阻塞操作无法响应状态变化:syncFadeLed(3秒)和k_msleep(1秒)都是长阻塞操作,期间无法及时检测lightMode的变化。

针对这些问题,给出基于Zephyr RTOS的具体实现方案:

1. 重构为独立线程 + 事件通知

使用Zephyr的k_event实现主线程对子线程的及时唤醒,同时将共享状态改为原子变量避免数据竞争。

第一步:定义线程和事件变量

在DroneService类中添加:

#include <zephyr/kernel.h>
#include <atomic>

class DroneService {
private:
    std::atomic<LightModes> lightMode{Stop}; // 原子变量保证线程安全
    LightModes pastLightMode{Stop};
    struct k_event light_mode_event; // 用于状态变化通知
    k_thread light_thread;
    K_THREAD_STACK_DEFINE(light_thread_stack, 1024); // 线程栈

    static void lightControlThread(void* arg);
    // ...其他成员
};

第二步:初始化线程和事件

在DroneService的构造函数或初始化方法中:

DroneService::DroneService() {
    k_event_init(&light_mode_event);
    k_thread_create(&light_thread, light_thread_stack,
                    K_THREAD_STACK_SIZEOF(light_thread_stack),
                    lightControlThread, this, NULL, NULL,
                    K_PRIO_COOP(10), 0, K_NO_WAIT);
}

第三步:实现线程逻辑

将原work handler的逻辑迁移到独立线程,用k_poll实现可中断的延迟,确保能及时响应状态变化:

void DroneService::lightControlThread(void* arg) {
    DroneService* droneService = static_cast<DroneService*>(arg);
    struct k_poll_event event = K_POLL_EVENT_INITIALIZER(
        K_POLL_TYPE_EVENT, K_POLL_MODE_NOTIFY_ONLY, &droneService->light_mode_event
    );

    while (true) {
        LightModes currentMode = droneService->lightMode.load(std::memory_order_acquire);

        if (currentMode == Stop) {
            bool stopFade = false;

            // 从100 fade到10(原3秒,拆分为90步,每步≈33ms)
            for (int brightness = 100; brightness >= 10 && !stopFade; brightness--) {
                droneService->rightLed->setBrightness(brightness);
                // 等待33ms,或被事件唤醒
                int ret = k_poll(&event, 1, K_MSEC(33));
                if (ret == 0) {
                    k_event_reset(&droneService->light_mode_event);
                    stopFade = true;
                }
                currentMode = droneService->lightMode.load(std::memory_order_acquire);
                if (currentMode != Stop) stopFade = true;
            }
            if (stopFade) continue;

            // 等待1秒,可中断
            int ret = k_poll(&event, 1, K_SEC(1));
            if (ret == 0) {
                k_event_reset(&droneService->light_mode_event);
                continue;
            }
            currentMode = droneService->lightMode.load(std::memory_order_acquire);
            if (currentMode != Stop) continue;

            // 从10 fade到100(原3秒,拆分为90步)
            for (int brightness = 10; brightness <= 100 && !stopFade; brightness++) {
                droneService->rightLed->setBrightness(brightness);
                int ret = k_poll(&event, 1, K_MSEC(33));
                if (ret == 0) {
                    k_event_reset(&droneService->light_mode_event);
                    stopFade = true;
                }
                currentMode = droneService->lightMode.load(std::memory_order_acquire);
                if (currentMode != Stop) stopFade = true;
            }
            if (stopFade) continue;

            // 等待1秒,可中断
            ret = k_poll(&event, 1, K_SEC(1));
            if (ret == 0) {
                k_event_reset(&droneService->light_mode_event);
            }
        } else if (currentMode == Running) {
            // 仅在模式切换时执行一次fade
            std::lock_guard<std::mutex> lock(droneService->mode_mutex); // 保护pastLightMode
            if (droneService->pastLightMode != Running) {
                LOG_DBG("*************Running\n");
                droneService->pastLightMode = Running;
                droneService->rightLed->syncFadeLed(10, 100, 500);
            }
            // 等待状态变化事件
            k_event_wait(&droneService->light_mode_event, K_FOREVER);
            k_event_reset(&droneService->light_mode_event);
        } else {
            // 其他模式:等待状态变化
            k_event_wait(&droneService->light_mode_event, K_FOREVER);
            k_event_reset(&droneService->light_mode_event);
        }
    }
}

第四步:修改状态设置方法

主线程设置模式后,通过事件通知子线程:

void DroneService::setUpLightsMode(LightModes mode){
    lightMode.store(mode, std::memory_order_release);
    k_event_post(&light_mode_event);
}

2. 关键优化点说明

  • 原子变量:lightMode用std::atomic修饰,保证多线程读写的原子性,避免数据竞争。
  • 可中断延迟:用k_poll替代k_msleep,既能实现定时,又能在状态变化时被立即唤醒。
  • 拆分阻塞操作:将长时长的syncFadeLed拆分为逐帧调整亮度的循环,每帧都检查状态,确保能快速响应模式切换。
  • 独立线程:避免占用系统工作队列,保证其他任务正常执行。

备选方案:使用互斥锁 + 条件变量(标准C++)

如果不依赖Zephyr的API,也可以用标准C++的std::mutex和std::condition_variable实现:

#include <mutex>
#include <condition_variable>

class DroneService {
private:
    std::mutex mode_mutex;
    std::condition_variable mode_cv;
    LightModes lightMode{Stop};
    LightModes pastLightMode{Stop};
    // ...
};

// 主线程设置模式
void DroneService::setUpLightsMode(LightModes mode){
    std::lock_guard<std::mutex> lock(mode_mutex);
    lightMode = mode;
    mode_cv.notify_one();
}

// 子线程逻辑片段(替换k_poll部分)
std::unique_lock<std::mutex> lock(droneService->mode_mutex);
// 等待1秒或被通知
if (droneService->mode_cv.wait_for(lock, std::chrono::seconds(1),
    [droneService](){ return droneService->lightMode != Stop; })) {
    // 模式已变化,退出循环
    continue;
}

内容的提问来源于stack exchange,提问作者Rubén Méndez Vallés

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 01:19:53