- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
#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)
{_isEmpty=true; _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)//если очередь пуста говорим что наш элемент пока первый и последний
{
_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;
}
IKing 02.07.2014 14:25 # +2
bormand 02.07.2014 15:57 # 0
IKing 02.07.2014 16:15 # −1
Кажется поправил.
bormand 02.07.2014 16:21 # +2
- сразу после создания isEmpty == true, tail == nullptr;
- первый тред входит в pop, берет lockTail, видит nullptr в tail;
- второй тред входит в push, берет lockHead, видит true в isEmpty;
- первый тред ждет lockHead
- второй тред ждет lockTail
IKing 03.07.2014 09:19 # −1
Получается разблокировав lockHead до wait я избавлюсь от проблемы?
bormand 03.07.2014 10:42 # +3
Вот к примеру: http://www.boost.org/doc/libs/1_55_0/doc/html/lockfree.html
IKing 03.07.2014 11:28 # +3
brutushafens 02.07.2014 23:12 # +1
brutushafens 02.07.2014 16:36 # −5
laMer007 02.07.2014 16:40 # +1
Relacy Race Detector
eth0 03.07.2014 20:44 # +2
TarasB 03.07.2014 10:56 # +2
bormand 03.07.2014 11:02 # +4
Ну-ну.
3.14159265 03.07.2014 13:51 # 0
Хотя что подразумевать под "просто" - придумать и главное доказать корректность изобретенного алгоритма, вряд ли. А реализовать чужое, передрав псевдокод - это сравнительно просто.
В крестах еще ABA вылазит, в мусоросборных языках с этим чуть проще.
TarasB 03.07.2014 14:26 # +1
roman-kashitsyn 03.07.2014 11:13 # +1
> просто
Если у тебя будет ровно один производитель и ровно один потребитель, то да. И то там блокировку на переполнения кольцевого буфера надо.
3.14159265 03.07.2014 13:50 # 0
Не надо. Притом что у него связная очередь, а не на буфере.
http://www.csie.nctu.edu.tw/~tlhuang/Papers/ICPADS00.pdf
roman-kashitsyn 03.07.2014 13:51 # +1
То, что можно сложно и без лока, я в курсе.
3.14159265 03.07.2014 13:54 # 0
Я борманду ответил про "просто". Смотря что - реализовывать чужое или придумывать своё, или вообще "просто" - имелось ввиду без лочек.
Для связных существует Michael & Scott.
laMer007 03.07.2014 15:11 # 0
3.14159265 03.07.2014 16:27 # +1
http://www.computer.org/csdl/proceedings/icpads/2000/0568/00/05680470.pdf
tirinox 03.07.2014 11:24 # +1
Люди, зачем вам const в языке, если у вас столько способов его снять ? :)
roman-kashitsyn 03.07.2014 11:27 # +3
absolut 04.07.2014 06:46 # 0
bormand 04.07.2014 07:06 # 0
kegdan 03.07.2014 11:30 # −6
Abbath 03.07.2014 13:14 # 0
kegdan 03.07.2014 13:24 # 0
Xom94ok 03.07.2014 14:34 # 0
laMer007 03.07.2014 12:04 # 0
IKing 03.07.2014 15:41 # +1