MST
星途 面试题库

面试题:C++ 实现线程安全的队列

在多线程环境下,使用C++ 实现一个线程安全的队列。要求使用互斥锁(mutex)、条件变量(condition variable)等机制来保证线程安全,并且实现入队和出队操作。详细说明你在实现过程中是如何避免死锁、数据竞争等问题的。
22.8万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试
#include <iostream>
#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>

template <typename T>
class ThreadSafeQueue {
private:
    std::queue<T> queue_;
    std::mutex mutex_;
    std::condition_variable cond_;
public:
    void enqueue(T item) {
        std::unique_lock<std::mutex> lock(mutex_);
        queue_.push(item);
        lock.unlock();
        cond_.notify_one();
    }

    bool dequeue(T& item) {
        std::unique_lock<std::mutex> lock(mutex_);
        cond_.wait(lock, [this] { return!queue_.empty(); });
        if (queue_.empty()) {
            return false;
        }
        item = queue_.front();
        queue_.pop();
        return true;
    }
};

避免死锁

  1. 锁的粒度控制:在enqueue函数中,获取锁后执行入队操作,然后立即解锁,减少锁的持有时间,避免在持有锁的情况下执行可能引起死锁的操作(如调用其他可能获取锁的函数)。
  2. 条件变量的使用:在dequeue函数中,使用std::condition_variablewait函数时,传递了一个谓词[this] { return!queue_.empty(); }。这样,wait函数在等待条件变量被通知时会自动释放锁,避免了在等待过程中一直持有锁导致的死锁问题。当条件变量被通知后,wait函数重新获取锁,确保对队列的操作是线程安全的。

避免数据竞争

  1. 互斥锁的使用:通过std::mutex确保对队列的访问是线程安全的。在enqueuedequeue函数中,都通过std::unique_lock<std::mutex>来获取锁,在作用域结束时自动释放锁,保证同一时间只有一个线程能够访问队列,避免数据竞争。
  2. 条件变量同步std::condition_variable用于线程间的同步。在dequeue中,线程等待队列不为空的条件,只有当队列中有元素时才会被唤醒,从而避免了从空队列中取出数据的竞争问题。在enqueue中,当新元素入队后,通过cond_.notify_one()通知等待在条件变量上的一个线程,确保等待线程能够及时得知队列状态的变化。