Skip to content

[Bug] 关于workqueue的一些问题 #11144

@milo-9

Description

@milo-9

RT-Thread Version

5.2.2-master

Hardware Type/Architectures

All

Develop Toolchain

Other

Describe the bug

rt_workqueue_cancel_work_sync 在某些情况下是无法彻底取消任务的,某些任务会在执行完成后重新将自身提交到工作队列中,但是工作队列的删除是在执行任务前执行的,导致等待到信号量后,任务对象仍然在工作队列中,这会导致很多潜在的问题。例如调用者在同步取消任务后,可能会释放一些共享资源,结果任务重新执行访问野指针导致系统崩溃
rt_workqueue_destroy 没有同步取消任务,就盲目将工作线程关闭,如果工作线程执行的任务申请了一些资源,还没有释放,被强行关闭后,这部分资源就得不到释放
rt_workqueue_cancel_all_work 使用了rt_enter_critical来保护临界资源,但是在多核系统上,这是不安全的,其他接口使用的也是自旋锁的方式实现的临界保护
另外queue->work_current这个成员我认为需要保证原子性,有些地方并没有做到这一点

下面是一些测试代码,这些写法正常人不会这么写,这里只是为了模拟一些极端情况下可能出现的抢占问题,当然可能是我的理解有问题,如果各位认同我的这些看法的话,我可以提交一个PR

#include <rtthread.h>
#include <ipc/workqueue.h>

static void work_func(struct rt_work *work, void *data)
{
    rt_kprintf("%d\n", rt_tick_get());
    char *buf = rt_malloc(128);
    // 一些其他工作
    rt_thread_delay(RT_TICK_PER_SECOND / 100); // 模拟被抢占
    rt_free(buf);
    rt_workqueue_submit_work((struct rt_workqueue *)data, work, RT_TICK_PER_SECOND / 100); // 重新提交任务
}

static int wq_cancel_work_sync_test(int argc, char *argv[])
{
    // 保证工作队列线程优先级高于shell优先级,主要是为了模拟工作队列执行过程中被抢占
    struct rt_workqueue *wq = rt_workqueue_create("test", 512, 1);
    struct rt_work work;

    rt_work_init(&work, work_func, wq);
    rt_workqueue_submit_work(wq, &work, 0);
    rt_workqueue_cancel_work_sync(wq, &work);
    return 0; // work是栈上分配的,这里退出后,work实际还在工作队列中,会导致问题,这里这样做是为了直观体现rt_workqueue_cancel_work_sync并不可靠
}
MSH_CMD_EXPORT(wq_cancel_work_sync_test, workqueue cancel work sync test);

static int wq_destroy_test(int argc, char *argv[])
{
    // 保证工作队列线程优先级高于shell优先级,主要是为了模拟工作队列执行过程中被抢占
    struct rt_workqueue *wq = rt_workqueue_create("test", 512, 1);
    struct rt_work work;

    rt_work_init(&work, work_func, wq);
    rt_workqueue_submit_work(wq, &work, 0); // 这里提交任务后,任务会立即执行,但是任务中途又让出了CPU
    rt_workqueue_destroy(wq); // 任务让出CPU后,顺利执行到这里,销毁工作队列,但是工作队列中分配的内存将不会被释放
    return 0;
}
MSH_CMD_EXPORT(wq_destroy_test, workqueue destroy test);

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions