#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;
}
};
避免死锁
- 锁的粒度控制:在
enqueue
函数中,获取锁后执行入队操作,然后立即解锁,减少锁的持有时间,避免在持有锁的情况下执行可能引起死锁的操作(如调用其他可能获取锁的函数)。
- 条件变量的使用:在
dequeue
函数中,使用std::condition_variable
的wait
函数时,传递了一个谓词[this] { return!queue_.empty(); }
。这样,wait
函数在等待条件变量被通知时会自动释放锁,避免了在等待过程中一直持有锁导致的死锁问题。当条件变量被通知后,wait
函数重新获取锁,确保对队列的操作是线程安全的。
避免数据竞争
- 互斥锁的使用:通过
std::mutex
确保对队列的访问是线程安全的。在enqueue
和dequeue
函数中,都通过std::unique_lock<std::mutex>
来获取锁,在作用域结束时自动释放锁,保证同一时间只有一个线程能够访问队列,避免数据竞争。
- 条件变量同步:
std::condition_variable
用于线程间的同步。在dequeue
中,线程等待队列不为空的条件,只有当队列中有元素时才会被唤醒,从而避免了从空队列中取出数据的竞争问题。在enqueue
中,当新元素入队后,通过cond_.notify_one()
通知等待在条件变量上的一个线程,确保等待线程能够及时得知队列状态的变化。