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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions