如何让Twister中Zephyr任务线程与测试线程并行运行?
问题
我基于Zephyr开发了一个包含多个交互任务的应用,其中一个任务负责读写虚拟仪表与阀门。现在要为项目添加测试,验证该任务能否正常运行并正确响应。
我已在Twister中启动了该任务的线程,但它无法与测试线程并行运行。当前只能通过k_sleep()暂停测试线程,但这会导致获取任务剩余水量、虚拟仪表数值等辅助函数无法正常工作。
相关代码如下:
CMake配置:
cmake_minimum_required(VERSION 3.13.1) set(APP_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../..) list(APPEND ZEPHYR_EXTRA_MODULES ${APP_ROOT}/src/drivers/meter) list(APPEND ZEPHYR_EXTRA_MODULES ${APP_ROOT}/src/drivers/valve) list(APPEND SYSCALL_INCLUDE_DIRS ${APP_ROOT}/include/) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(MyProject) zephyr_include_directories(${ZEPHYR_BASE}/include/zephyr/drivers/) # C sources target_sources(app PRIVATE src/main.c) target_sources(app PRIVATE ${APP_ROOT}/src/task/MterTask.c)
任务线程定义:
K_THREAD_DEFINE(metertask_id, METER_TASK_STACKSIZE, _meter_thread, NULL, NULL, NULL, METER_TASK_PRIORITY, K_ESSENTIAL, 0);
请问是否有办法让Twister中任务线程与测试线程并行运行?
解决方案
以下几种方案可以实现Twister测试线程与仪表任务线程的并行运行:
1. 调整线程优先级
Zephyr采用抢占式调度,若测试线程优先级高于仪表任务,会持续占用CPU导致后者无法运行:
- 检查
CONFIG_TEST_THREAD_PRIORITY(测试线程默认优先级),确保其值大于等于METER_TASK_PRIORITY的定义值。可以在prj.conf中配置:CONFIG_TEST_THREAD_PRIORITY=5 - 也可以在测试代码中动态调整测试线程优先级:
k_thread_priority_set(k_current_get(), METER_TASK_PRIORITY + 1);
2. 用同步原语替代k_sleep()
k_sleep()会强制挂起测试线程,改用信号量、事件等同步机制,既能保证线程并行,又能精准控制测试时机:
// 全局定义信号量(或静态初始化) struct k_sem meter_op_done_sem; // 测试初始化时初始化信号量 static void test_setup(void) { k_sem_init(&meter_op_done_sem, 0, 1); } // 仪表任务中完成读写操作后释放信号量 void _meter_thread(void *p1, void *p2, void *p3) { while (1) { // 执行仪表/阀门读写逻辑 update_meter_and_valve(); // 操作完成后通知测试线程 k_sem_give(&meter_op_done_sem); // 任务自身的循环延迟(按需设置) k_msleep(100); } } // 测试线程中等待信号量,替代k_sleep() ZTEST(meter_tests, test_meter_response) { // 触发仪表任务操作(若需要) trigger_meter_task(); // 等待操作完成 k_sem_take(&meter_op_done_sem, K_FOREVER); // 此时安全调用辅助函数验证结果 int remaining_water = get_remaining_water(); zassert_equal(remaining_water, EXPECTED_WATER, "剩余水量不符"); }
3. 启用必要的Zephyr配置
确保项目配置中开启多线程和抢占调度支持:
CONFIG_MULTITHREADING=y CONFIG_SCHED_PREEMPT=y CONFIG_TEST=y CONFIG_TEST_RUNNER=y
4. 测试线程主动让出CPU
如果测试线程有循环检查逻辑,加入k_yield()主动释放CPU,让仪表任务获得运行机会:
ZTEST(meter_tests, test_meter_loop) { int target_val = 100; while (true) { int current_val = get_meter_value(); if (current_val == target_val) { break; } // 主动让出CPU给其他线程 k_yield(); } zassert_true(true, "仪表数值达到目标"); }
内容的提问来源于stack exchange,提问作者obvg
相关产品推荐
相关产品推荐

