Предположим, у меня есть класс ThreadQueue, содержащий std::queue
, и я передаю его экземпляр в std::ref
потоку. Предположим далее, что этот поток 1 (основной поток) создает и хранит объект ThreadQueue и помещает в него сообщения, а задача второго потока состоит в том, чтобы принимать эти сообщения по мере их поступления и помещать их где-нибудь, скажем, записывать их в файл журнала.
Класс выглядит следующим образом:
#include <queue>
#include <mutex>
#include <condition_variable>
using namespace std;
template <typename T>
class ThreadQueue
{
queue<T> q_;
mutex mtx;
unique_lock<mutex> lck;
condition_variable cv;
public:
ThreadQueue() { lck = unique_lock<mutex>(mtx); }
~ThreadQueue() { if (lck.owns_lock()) lck.unlock(); }
void enqueue (const T&);
T dequeue ();
};
template <typename T>
void ThreadQueue<T>::enqueue (const T& t)
{
lck.lock();
q_.push(t);
lck.unlock();
cv.notify_one();
}
template <typename T>
T ThreadQueue<T>::dequeue ()
{
cv.wait(lck);
lck.lock();
T t = q_.front(); // let's assume that's a copy assignment, because
q_.pop(); // pop() calls the descructor.
lck.unlock();
return t;
}
Затем в основном звучит мелодия:
ThreadQueue<std::pair<int, std::string>> logs;
// and maybe something like:
std::thread logger(std::ref(logs));
Важнейшая строка - cv.wait(lck);
В документации четко указано, что lck
требуется объект unique_lock, объект мьютекса которого в данный момент заблокирован этим потоком.
Теперь возникает вопрос: кто на самом деле блокирует мьютекс и кому принадлежит блокировка, поток 1 или нить 2?