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

pthread互斥锁失效求助:未解锁时其他线程可进入临界区

互斥锁失效:线程重复锁定同一pthread_mutex_t的问题分析

问题现象

运行日志显示同一互斥锁被两个线程同时持有,违背互斥锁的基本语义:

checkEvents lock eventloop mutex. <-- 互斥锁已被锁定
Eventloop::remove lock eventloop mutex. <-- 另一线程再次锁定同一互斥锁
checkEvents unlock eventloop mutex.

核心原因分析

问题的根源在于Timer类中多处锁操作错误,触发了未定义行为,间接破坏了Eventloop互斥锁的正常工作:

1. 锁操作拼写错误(致命问题)

Timer的析构函数、start方法、handle方法中,均将pthread_mutex_unlock误写为pthread_mutex_lock,导致同一线程对非递归互斥锁重复加锁。pthread默认互斥锁为非递归类型,重复加锁会触发未定义行为——操作系统可能认为锁状态损坏,进而允许其他线程绕过互斥逻辑。

2. 内存删除逻辑错误

Eventloop::remove方法中,错误地删除eventList.back()而非当前匹配的事件元素,导致内存管理混乱,进一步加剧未定义行为的发生。

3. Timer成员互斥锁未初始化

Timer类的成员互斥锁mutex未在构造函数中初始化,直接使用会导致锁状态异常。

具体代码问题点

Timer.cpp中的错误锁操作

  • 析构函数:最后一行应为unlock而非lock
    Timer::~Timer()
    {
        std::cout << "Timer destructor start\n";
        pthread_mutex_lock(&mutex);
        Eventloop::remove(&timerEvent);
        pthread_mutex_lock(&mutex);  // ❌ 应为pthread_mutex_unlock
        std::cout << "Timer destructor end \n";
    }
    
  • start方法:修改参数后应为unlock而非lock
    void Timer::start(uint16_t ms)
    {
        pthread_mutex_lock(&mutex);
        durMs = ms;
        startTime = getTimeMs();
        pthread_mutex_lock(&mutex);  // ❌ 应为pthread_mutex_unlock
        stopFlag = false;
    }
    
  • handle方法:逻辑处理后应为unlock而非lock
    void Timer::handle()
    {
        pthread_mutex_lock(&mutex);
        if (!stopFlag) {
            if (getTimeMs() - startTime >= durMs) {
                timerTask->runTimerTask();
                startTime = getTimeMs();
            }
        }
        pthread_mutex_lock(&mutex);  // ❌ 应为pthread_mutex_unlock
    }
    

Eventloop.cpp中的删除逻辑错误

void Eventloop::remove(Event **event)
{
    pthread_mutex_lock(&mutex);
    std::cout << "Eventloop::remove lock eventloop mutex. \n";
    std::list<Event *>::iterator it;
    for(it = eventList.begin() ; it != eventList.end() ; it++) {
        std::cout << "event = " << (*it) << "\n";
        if((*it) == *event) {
            delete eventList.back();  // ❌ 应删除当前匹配的(*it)
            eventList.remove(*event);
        }
    }
    pthread_mutex_unlock(&mutex);
    std::cout << "Eventloop::remove unlock eventloop mutex. \n";
}

修复方案

1. 修正Timer类的锁操作

将所有错误的pthread_mutex_lock替换为pthread_mutex_unlock,并初始化/销毁Timer的成员互斥锁:

// Timer构造函数:初始化成员互斥锁
Timer::Timer(TimerTask *_timerTask)
{
    pthread_mutex_init(&mutex, NULL);
    timerEvent = new TimerEvent(this);
    Eventloop::append(&timerEvent);
    std::cout << "Event in Timer Constructor= " << timerEvent << "\n";
    timerTask = _timerTask;
    stopFlag = false;
}

// Timer析构函数:修正锁操作并销毁互斥锁
Timer::~Timer()
{
    std::cout << "Timer destructor start\n";
    pthread_mutex_lock(&mutex);
    Eventloop::remove(&timerEvent);
    pthread_mutex_unlock(&mutex);
    pthread_mutex_destroy(&mutex);
    std::cout << "Timer destructor end \n";
}

// Timer::start:修正锁操作
void Timer::start(uint16_t ms)
{
    pthread_mutex_lock(&mutex);
    durMs = ms;
    startTime = getTimeMs();
    pthread_mutex_unlock(&mutex);
    stopFlag = false;
}

// Timer::handle:修正锁操作
void Timer::handle()
{
    pthread_mutex_lock(&mutex);
    if (!stopFlag) {
        if (getTimeMs() - startTime >= durMs) {
            timerTask->runTimerTask();
            startTime = getTimeMs();
        }
    }
    pthread_mutex_unlock(&mutex);
}

2. 修正Eventloop::remove的删除逻辑

改为删除当前匹配的元素,并避免迭代器失效:

void Eventloop::remove(Event **event)
{
    pthread_mutex_lock(&mutex);
    std::cout << "Eventloop::remove lock eventloop mutex. \n";
    std::list<Event *>::iterator it;
    for(it = eventList.begin() ; it != eventList.end() ; ) {
        std::cout << "event = " << (*it) << "\n";
        if((*it) == *event) {
            delete (*it);
            it = eventList.erase(it);
        } else {
            ++it;
        }
    }
    pthread_mutex_unlock(&mutex);
    std::cout << "Eventloop::remove unlock eventloop mutex. \n";
}

验证建议

  1. 运行修复后的代码,观察日志是否再出现同一互斥锁被多线程同时持有的情况。
  2. 添加线程ID打印(如pthread_self()),确认加锁/解锁操作的线程一致性。
  3. 显式指定互斥锁类型为普通锁,避免依赖默认行为:
    pthread_mutexattr_t attr;
    pthread_mutexattr_init(&attr);
    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
    pthread_mutex_init(&Eventloop::mutex, &attr);
    pthread_mutexattr_destroy(&attr);
    

内容的提问来源于stack exchange,提问作者Pouya Imani

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 13:07:33