- 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
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
#include <iostream>
#include <list>
#include <queue>
#include <memory>
#include <mutex>
#include <condition_variable>
#include <type_traits>
#include <assert.h>
using namespace std;
template<class Data>
class UnboundedQueueForNonThrowMovable
{
static_assert(std::is_nothrow_move_constructible<Data>::value, "Data must be nonthrow movable type.");
static_assert(!std::is_array<Data>::value, "Data must not be c-array.");
public:
typedef Data value_type;
private:
typedef std::queue<Data, std::list<Data>> Queue;
typedef std::unique_lock<std::mutex> Lock;
Queue _queue;
std::mutex _lockQueue;
std::condition_variable _pushToQueue;
UnboundedQueueForNonThrowMovable(const UnboundedQueueForNonThrowMovable&) = delete;
UnboundedQueueForNonThrowMovable(UnboundedQueueForNonThrowMovable&&) = delete;
UnboundedQueueForNonThrowMovable& operator=(const UnboundedQueueForNonThrowMovable&) = delete;
UnboundedQueueForNonThrowMovable& operator=(UnboundedQueueForNonThrowMovable&&) = delete;
public:
UnboundedQueueForNonThrowMovable(void){}
void push(Data&& data)
{
Lock lockerQueue(this->_lockQueue);
this->_queue.push(std::move(data));
this->_pushToQueue.notify_all();//_condition.notify_one(); most optimal, but can cause deadlock.
}
void push(Data& data)
{
this->push(std::move(data));
}
bool emptyUnstable(void) const
{
Lock lockerQueue(this->_lockQueue);
return this->_queue.empty();
}
Data pop(void)
{
Lock lockerQueue(this->_lockQueue);
this->_pushToQueue.wait(lockerQueue, [this](void){return !this->_queue.empty();});
assert(!this->_queue.empty());
Data result = std::move(this->_queue.front());
this->_queue.pop();
return result;
}
template< class Rep, class Period>
Data pop(const std::chrono::duration<Rep, Period> WaitDuration)
{
Lock lockerQueue(this->_lockQueue);
if(!this->_pushToQueue.wait(lockerQueue, WaitDuration, [this](void){return !this->_queue.empty();}))
return Data();
assert(!this->_queue.empty());
Data result = std::move(this->_queue.front());
this->_queue.pop();
return result;
}
};
template<class Data>
using UnboundedQueueForUniquePtr = UnboundedQueueForNonThrowMovable<std::unique_ptr<Data>>;
template<class Data>
using UnboundedQueueForSharedPtr = UnboundedQueueForNonThrowMovable<std::shared_ptr<const Data>>;
template<class Data>
using UnboundedQueue = UnboundedQueueForUniquePtr<Data>;
int main() {
cout<<"ok"<<endl;
{
//UnboundedQueueForSharedPtr<int>::value_type == std::shared_ptr<const int>
UnboundedQueueForSharedPtr<int> queueSharedPtr;
//auto a = std::make_shared<const int>(45);
auto a = std::make_shared<int>(45);
assert(a);
queueSharedPtr.push(a);
assert(!a);//Fired if you use "auto a = std::make_shared<int>(45)" below. It is compiler bug, I think, because previus code line must cause compile error.
auto b = queueSharedPtr.pop();//std::shared_ptr<const int>
assert(b);
cout<<*b<<endl;
assert(*b==45);