#include <iostream>
#include <memory>
#include <mutex>
#include <condition_variable>
#include <atomic>
typedef ::std::unique_lock<::std::mutex> TLock;
using namespace std;
template<typename T>
class TQueueElement
{
public:
T _data;
std::shared_ptr<TQueueElement<T> > _prev;
mutable ::std::mutex _lockElem;
public:
TQueueElement(T data):_data(data),_prev(nullptr){};
virtual ~TQueueElement(){};
};
template<typename T>
class TQueue
{
private:
mutable ::std::mutex _lockHead;
mutable ::std::mutex _lockTail;
::std::condition_variable _pushToQueue;
std::atomic<bool> _isEmpty;
std::shared_ptr<TQueueElement<T> > _tail;
std::shared_ptr<TQueueElement<T> > _head;
public:
TQueue():_lockHead(),_isEmpty(true){};
virtual ~TQueue(){};
///получаем элемент из очереди
T pop()
{
TLock lock(_lockTail);//блокируем все получения из очереди
if (_tail==nullptr)
{
TLock lockHead(_lockHead);
if (_tail==nullptr)
{
_isEmpty=true;
lockHead.unlock();
_pushToQueue.wait(lock,[this](){return !_isEmpty;});//если очередь пуста ожидаем пока в ней чтото появиться
}
}
{
TLock lockTail(_tail->_lockElem); //блокируем последний элемент в очереди возможно к нему попробуют обратиться во время запихивания в очередь
auto data=_tail->_data;
_tail=_tail->_prev;
return data;
}
}
void push(T data)
{
auto el=std::shared_ptr<TQueueElement<T> >(new TQueueElement<T>(data));//заранее создаем элемент очереди
TLock lock(_lockHead);
if (_isEmpty)//если очередь пуста говорим что наш элемент пока первый и последний
{
{
TLock lock(_lockTail);
_head=el;
_tail=el;
_isEmpty=false;
}
_pushToQueue.notify_all();
}else//если очередь не пуста
{
{
TLock lockHead(_head->_lockElem); //блокируем голову от возможного обращения с хвоста
_head->_prev=el; //выставляем ссылку на новую голову у старой
}
_head=el;//выставляем новую голову
}
}
};
int main() {
TQueue<int> q;
q.push(7);
q.pop();
// your code goes here
return 0;
}