细粒度锁的极简单线程安全队列
template<typename T>
class ThreadsafeQueue
{
private:
struct Node
{
std::shared_ptr<T> data;
std::unique_ptr<T> next;
};
std::unique_ptr<Node> head;
Node* tail;
mutable std::mutex headMutex;
mutable std::mutex tailMutex;
std::condition_variable dataCond;
Node* getTail () const
{
std::lock_guard<std::mutex> lock(tailMutex);
return tail;
}
std::unique_lock<std::mutex> waitForData();
std::unique_ptr<Node> popHead ()
{
std::lock_guard<std::mutex> lock(headMutex);
auto oldHead = std::move(head);
head = std::move(oldHead->next);
return oldHead;
}
std::unique_ptr<Node> waitPopHead ()
{
std::unique_lock<std::mutex> lock(waitForData ());
return popHead ();
}
std::unique_ptr<Node> waitPopHead (T& popedValue)
{
std::unique_lock<std::mutex> lock(waitForData ());
popedValue = std::move(*head->data);
return popHead ();
}
std::unique_ptr<Node> tryPopHead ()
{
std::lock_guard<std::mutex> lock(headMutex);
if (head.get () == getTail ()){
return std::unique_ptr<Node>();
}
return popHead ();
}
std::unique_ptr<Node> tryPopHead (T& popedValue)
{
std::lock_guard<std::mutex> lock(headMutex);
if (head.get () == getTail ()){
return std::unique_ptr<Node>();
}
popedValue = std::move(*head->data);
return popHead ();
}
public:
ThreadsafeQueue():
head(std::make_shared<T>()), tail(head.get ())
{}
ThreadsafeQueue(const ThreadsafeQueue&) = delete;
ThreadsafeQueue& operator=(const ThreadsafeQueue&) = delete;
std::shared_ptr<T> tryPop();
bool tryPop(T&);
std::shared_ptr<T> waitAndPop();
void waitAndPop(T& value);
void push(T newValue);
bool empty();
};
template<typename T>
void ThreadsafeQueue<T>::push (T newValue)
{
auto const newData = std::make_shared<T>(std::move(newValue));
auto newNext = std::make_unique<Node>();
auto newTail = newNext.get();
std::lock_guard<std::mutex> lock(tailMutex);
tail->next = std::move(newNext);
tail->data = newData;
tail = newTail;
dataCond.notify_one ();
}
template<typename T>
inline std::unique_lock<std::mutex> ThreadsafeQueue<T>::waitForData ()
{
std::unique_lock<std::mutex> lock(headMutex);
dataCond.wait(lock, [&]{return head != getTail ();});
return std::move(lock);
}
template<typename T>
inline bool ThreadsafeQueue<T>::empty ()
{
std::lock_guard<std::mutex> lock(headMutex);
return (head.get () == getTail ());
}
template<typename T>
inline std::shared_ptr<T> ThreadsafeQueue<T>::waitAndPop ()
{
auto const oldHead = waitPopHead ();
return oldHead->data;
}
template<typename T>
inline void ThreadsafeQueue<T>::waitAndPop (T& popedValue)
{
waitPopHead (popedValue);
}
template<typename T>
inline std::shared_ptr<T> ThreadsafeQueue<T>::tryPop ()
{
auto const oldHead = tryPopHead();
return oldHead? oldHead->data : std::shared_ptr<T>();
}
template<typename T>
inline bool ThreadsafeQueue<T>::tryPop (T& popedValue)
{
auto const oldHead = tryPopHead (popedValue);
return oldHead;
}