Skip to content

[Bug] rt_thread_detach分离一个持有未释放mutex的线程时是否该释放其mutex #10542

@eatvector

Description

@eatvector

RT-Thread Version

master

Hardware Type/Architectures

all

Develop Toolchain

GCC

Describe the bug

1.如果存在这种情况,线程B持有mutex未释放的情况下,线程A使用rt_thread_detach来分离线程B,线程A是否有必要在关闭线程B后释放其持有的mutex.例如下面的测试代码在目前主线分支中,rt_thread_detach的实现并不会释放被分离线程thread1持有的mutex:

#include <rtthread.h>

#define THREAD_PRIORITY      25
#define THREAD_STACK_SIZE    4096
#define THREAD_TIMESLICE     5


static rt_uint8_t thread1_stack[THREAD_STACK_SIZE];
static struct rt_thread thread1;

/* 定义互斥控制块 */
static rt_mutex_t test_mutex = RT_NULL;

/* 线程1入口函数 */
static void thread1_entry(void *parameter)
{
    /* 第一次获取互斥量 */
    rt_kprintf("thread1 try to take mutex first time\n");
    rt_mutex_take(test_mutex, RT_WAITING_FOREVER);
    rt_kprintf("thread1 take mutex first time success\n");

    while(1) { rt_thread_mdelay(1000); }
}

int mutex_recursive_test(void)
{
    /* 创建递归互斥量 */
    test_mutex = rt_mutex_create("test_mutex", RT_IPC_FLAG_PRIO);
    if (test_mutex == RT_NULL) {
        rt_kprintf("create mutex failed\n");
        return -1;
    }

    /* 初始化静态线程 */
    rt_thread_init(&thread1,
                  "thread1",
                  thread1_entry,
                  RT_NULL,
                  &thread1_stack[0],
                  sizeof(thread1_stack),
                  THREAD_PRIORITY,
                  THREAD_TIMESLICE);

    /* 启动线程 */
    rt_thread_startup(&thread1);

    /* 等待线程运行 */
    rt_thread_mdelay(100);

    /* 验证主线程无法获取被持有的互斥量 */
    rt_kprintf("main thread try to take mutex\n");
    if (rt_mutex_take(test_mutex, 1000) == RT_EOK) {
        rt_kprintf("[ERROR] main thread take mutex success! This should not happen!\n");
        rt_mutex_release(test_mutex);
    } else {
        rt_kprintf("main thread take mutex timeout, as expected\n");
    }

    /* 分离静态线程(应自动释放其持有的锁) */
    rt_kprintf("main thread detach thread1\n");
    rt_thread_detach(&thread1);

    /* 验证互斥量是否被正确释放 */
    rt_kprintf("main thread try to take mutex after detach\n");
    if (rt_mutex_take(test_mutex, 1000) == RT_EOK) {
        rt_kprintf("main thread take mutex success after detach\n");
        rt_mutex_release(test_mutex);
    } else {
        rt_kprintf("[BUG] main thread still cannot take mutex! _thread_detach_from_mutex bug triggered!\n");
    }

    /* 清理资源 */
    rt_mutex_delete(test_mutex);

    return 0;
}

/* 导出到 msh 命令列表 */
MSH_CMD_EXPORT(mutex_recursive_test, mutex recursive test);

上面的代码中,当前线程在尝试分离thread1后,无法获取thread1持有的锁,这是因为 rt_thread_detach 并未释放thread1持有的mutex,根据调用链:

rt_thread_detach ->_thread_detach -> _thread_detach_from_mutex -> rt_mutex_release

rt_thread_detach 要求调用线程与被分离线程不为同一线程,而rt_mutex_release 要求调用者和mutex持有者为同一线程,这导致实际上执行上面调用链时, rt_mutex_release不会释放被分离线程的mutex

2
不知道按照 rt_thread_detach的设计理念,是否需要释放被分离线程未释放的mutex呢?还是默认被分离线程应该在被分离前自己释放所有mutex,如果没有释放就什么也不做,当异常错误处理?

如果需要释放被分离线程的mutex,这里提供一个解决方案:#10545

Other additional context

No response

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