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

为何在condition_variable.wait_for前调用lock.unlock会导致线程阻塞?

定时器类中condition_variable.wait_for()前手动解锁导致线程阻塞的问题

我用观察者模式实现了一个简易定时器类,遇到一个特殊问题:为什么在condition_variable.wait_for()之前调用lock.unlock(),会导致下一次循环创建std::unique_lock<std::mutex>时线程发生阻塞?

相关定时器类代码如下:

class LittleTimer {
public:
    using ObserverData = std::tuple< std::chrono::steady_clock::time_point, std::function<void()> >;
    LittleTimer() : running_(false) {}

    ~LittleTimer() {
        Stop();
    }

    void
    AddObserver(std::chrono::milliseconds  interval,
                std::function<void()>      callback)
    {
        std::unique_lock<std::mutex> lock(mutex_);
        auto scheduled_time = std::chrono::steady_clock::now() + interval;
        observers_.push(ObserverData(scheduled_time, std::move(callback)));
        lock.unlock();
        condition_.notify_one();
    }

    void Start() {
        if (!running_) {
            running_ = true;
            thread_ = std::thread([this]() {
                    while (running_)
                    {
                        std::unique_lock<std::mutex> lock(mutex_);
                        if(!observers_.empty()) {
                            auto next_observer = observers_.top();
                            auto now = std::chrono::steady_clock::now();
                            if(std::get< 0 >(next_observer) <= now) { // 检查顶部事件的调度时间
                                auto observer = observers_.top();
                                observers_.pop();
                                lock.unlock();
                                // 调用观察者的回调
                                auto callback = std::get< 1 >(observer);
                                callback();
                            }
                            else
                            {
                                auto sleep_time = std::chrono::duration_cast<std::chrono::milliseconds>(std::get< 0 >(next_observer) - now);
                                // lock.unlock(); // !!!!!!!!!!!!!! 启用这行后,下一次循环会在创建lock时阻塞
                                condition_.wait_for(lock, sleep_time);
                            }
                        }
                        else
                        {
                            condition_.wait_for(lock, std::chrono::milliseconds(10));
                        }
                    }
                });
        }
    }

    void Stop() {
        if (running_) {
            running_ = false;
            condition_.notify_one();  // 唤醒线程使其退出
            if (thread_.joinable())
            {
                thread_.join();
            }
        }
    }

private:

    struct ObserverComparator
    {
        bool operator()(const ObserverData& left, const ObserverData& right) const {
            return std::get< 0 >(left) > std::get< 0 >(right);
        }
    };
    
    // 数据
    std::priority_queue< ObserverData, std::vector< ObserverData >, ObserverComparator >  observers_;
    // 同步组件
    std::thread                                                                           thread_;
    std::mutex                                                                            mutex_;
    std::condition_variable                                                               condition_;
    // 优雅关闭标记
    bool                                                                                  running_;
};

移除上述代码中标记的解锁语句后,代码可正常运行。测试代码如下:

class Observer {
public:
    virtual void OnTimerTick() = 0;
};

class TimerObserver : public Observer {
public:
    TimerObserver(const std::string& name) : name_(name), ticks_(0) {}

    void OnTimerTick() override {
        std::cout << "Observer " << name_ << " notified\n";
    }

private:
    std::string name_;
    int ticks_;
};

int main()
{
    LittleTimer timer;

    TimerObserver observer1("uno");
    TimerObserver observer2("due");
    
    timer.AddObserver(std::chrono::milliseconds(60), [&observer1]() {
        observer1.OnTimerTick();
    });

    timer.Start();

    std::this_thread::sleep_for(std::chrono::milliseconds(20));

    timer.AddObserver(std::chrono::milliseconds(10), [&observer2]() {
        observer2.OnTimerTick();
    });

    std::this_thread::sleep_for(std::chrono::milliseconds(60));

    timer.Stop();
    
    return 0;
}

问题原因分析

std::condition_variable的所有wait系列函数(包括wait_for())有严格的使用规则:调用时必须持有传入的unique_lock,核心逻辑是:

  1. wait_for()内部会自动释放锁,让其他线程可以访问共享资源(比如AddObserver中修改observers_);当等待结束(超时或被notify唤醒),函数会自动重新获取锁,确保后续操作共享数据的安全性。
  2. 如果你在调用wait_for()前手动解锁,就违反了这个规则,属于未定义行为。此时wait_for()操作的是一个未锁定的锁,会导致锁的状态混乱:比如等待结束后,函数尝试重新加锁,但锁可能已经被其他线程占用,或者之前的手动解锁操作导致锁的内部状态异常,最终在下一次循环创建unique_lock时,线程会阻塞在锁的获取步骤上。

正确用法总结

永远不要在调用condition_variable的wait系列函数前手动解锁传入的unique_lock,让函数内部自行处理锁的释放与重新获取,这是condition_variable设计的核心逻辑,也是保证线程安全的关键。

内容的提问来源于stack exchange,提问作者Budziwoj Man

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 08:37:35