2013-12-31 10:48:57 -05:00
|
|
|
|
2014-01-02 12:43:57 -05:00
|
|
|
// Queue.h
|
|
|
|
|
|
|
|
// Implements the cQueue class representing a thread safe queue
|
|
|
|
|
2013-12-21 09:43:32 -05:00
|
|
|
#pragma once
|
|
|
|
|
2014-01-02 12:43:57 -05:00
|
|
|
/*
|
2014-01-03 06:22:01 -05:00
|
|
|
Items can be added multiple times to a queue, there are two functions for
|
|
|
|
adding, EnqueueItem() and EnqueueItemIfNotPresent(). The first one always
|
|
|
|
enqueues the specified item, the second one checks if the item is already
|
|
|
|
present and only queues it if it isn't.
|
|
|
|
|
2014-01-02 12:43:57 -05:00
|
|
|
Usage:
|
2014-01-03 06:22:01 -05:00
|
|
|
To create a queue of type T, instantiate a cQueue<T> object. You can also
|
|
|
|
modify the behavior of the queue when deleting items and when adding items
|
|
|
|
that are already in the queue by providing a second parameter, a class that
|
|
|
|
implements the functions Delete() and Combine(). An example is given in
|
|
|
|
cQueueFuncs and is used as the default behavior.
|
2014-01-02 12:43:57 -05:00
|
|
|
*/
|
|
|
|
|
2014-01-05 09:15:44 -05:00
|
|
|
/// This empty struct allows for the callback functions to be inlined
|
2014-08-28 09:44:36 -04:00
|
|
|
template <class T>
|
2014-07-17 16:50:58 -04:00
|
|
|
struct cQueueFuncs
|
2013-12-21 09:43:32 -05:00
|
|
|
{
|
2014-01-05 09:15:44 -05:00
|
|
|
public:
|
|
|
|
|
|
|
|
/// Called when an Item is deleted from the queue without being returned
|
2014-07-22 18:36:13 -04:00
|
|
|
static void Delete(T) {}
|
2014-01-05 09:15:44 -05:00
|
|
|
|
|
|
|
/// Called when an Item is inserted with EnqueueItemIfNotPresent and there is another equal value already inserted
|
2014-02-23 15:23:35 -05:00
|
|
|
static void Combine(T & a_existing, const T & a_new)
|
|
|
|
{
|
|
|
|
UNUSED(a_existing);
|
|
|
|
UNUSED(a_new);
|
2014-07-22 18:36:13 -04:00
|
|
|
}
|
2013-12-31 10:48:57 -05:00
|
|
|
};
|
2013-12-21 09:43:32 -05:00
|
|
|
|
2014-01-05 09:15:44 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template <class ItemType, class Funcs = cQueueFuncs<ItemType> >
|
2013-12-21 09:43:32 -05:00
|
|
|
class cQueue
|
|
|
|
{
|
2014-01-05 09:15:44 -05:00
|
|
|
// The actual storage type for the queue
|
|
|
|
typedef typename std::list<ItemType> QueueType;
|
|
|
|
|
|
|
|
// Make iterator an alias for the QueueType's iterator
|
|
|
|
typedef typename QueueType::iterator iterator;
|
|
|
|
|
2013-12-21 09:43:32 -05:00
|
|
|
public:
|
2013-12-31 10:48:57 -05:00
|
|
|
cQueue() {}
|
|
|
|
~cQueue() {}
|
|
|
|
|
2014-01-05 09:15:44 -05:00
|
|
|
|
|
|
|
/// Enqueues an item to the queue, may block if other threads are accessing the queue.
|
|
|
|
void EnqueueItem(ItemType a_Item)
|
2013-12-31 10:48:57 -05:00
|
|
|
{
|
|
|
|
cCSLock Lock(m_CS);
|
2014-01-05 09:15:44 -05:00
|
|
|
m_Contents.push_back(a_Item);
|
2013-12-31 10:48:57 -05:00
|
|
|
m_evtAdded.Set();
|
|
|
|
}
|
2014-01-02 12:43:57 -05:00
|
|
|
|
2014-01-05 09:15:44 -05:00
|
|
|
|
|
|
|
/// Enqueues an item in the queue if not already present (as determined by operator ==). Blocks other threads from accessing the queue.
|
|
|
|
void EnqueueItemIfNotPresent(ItemType a_Item)
|
2013-12-31 10:48:57 -05:00
|
|
|
{
|
|
|
|
cCSLock Lock(m_CS);
|
|
|
|
|
2014-01-05 09:15:44 -05:00
|
|
|
for (iterator itr = m_Contents.begin(); itr != m_Contents.end(); ++itr)
|
2013-12-31 10:48:57 -05:00
|
|
|
{
|
2014-01-05 09:15:44 -05:00
|
|
|
if ((*itr) == a_Item)
|
|
|
|
{
|
|
|
|
Funcs::Combine(*itr, a_Item);
|
2013-12-31 10:48:57 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2014-01-05 09:15:44 -05:00
|
|
|
m_Contents.push_back(a_Item);
|
2013-12-31 10:48:57 -05:00
|
|
|
m_evtAdded.Set();
|
|
|
|
}
|
2014-01-02 12:43:57 -05:00
|
|
|
|
2014-01-05 09:15:44 -05:00
|
|
|
|
|
|
|
/// Dequeues an item from the queue if any are present.
|
|
|
|
/// Returns true if successful. Value of item is undefined if dequeuing was unsuccessful.
|
|
|
|
bool TryDequeueItem(ItemType & item)
|
2013-12-31 10:48:57 -05:00
|
|
|
{
|
|
|
|
cCSLock Lock(m_CS);
|
2014-01-05 09:15:44 -05:00
|
|
|
if (m_Contents.size() == 0)
|
2014-01-03 06:22:01 -05:00
|
|
|
{
|
2014-07-17 16:50:58 -04:00
|
|
|
return false;
|
2014-01-03 06:22:01 -05:00
|
|
|
}
|
2014-01-05 09:15:44 -05:00
|
|
|
item = m_Contents.front();
|
|
|
|
m_Contents.pop_front();
|
2014-01-02 07:32:55 -05:00
|
|
|
m_evtRemoved.Set();
|
2013-12-31 10:48:57 -05:00
|
|
|
return true;
|
|
|
|
}
|
2014-01-02 12:43:57 -05:00
|
|
|
|
2014-01-05 09:15:44 -05:00
|
|
|
|
|
|
|
/// Dequeues an item from the queue, blocking until an item is available.
|
|
|
|
ItemType DequeueItem(void)
|
2013-12-31 10:48:57 -05:00
|
|
|
{
|
|
|
|
cCSLock Lock(m_CS);
|
2014-01-05 09:15:44 -05:00
|
|
|
while (m_Contents.size() == 0)
|
2013-12-31 10:48:57 -05:00
|
|
|
{
|
2014-01-05 09:15:44 -05:00
|
|
|
cCSUnlock Unlock(Lock);
|
2013-12-31 10:48:57 -05:00
|
|
|
m_evtAdded.Wait();
|
|
|
|
}
|
2014-01-05 09:15:44 -05:00
|
|
|
ItemType item = m_Contents.front();
|
|
|
|
m_Contents.pop_front();
|
2014-01-02 07:32:55 -05:00
|
|
|
m_evtRemoved.Set();
|
|
|
|
return item;
|
2013-12-31 10:48:57 -05:00
|
|
|
}
|
2014-01-02 12:43:57 -05:00
|
|
|
|
2014-01-05 09:15:44 -05:00
|
|
|
|
|
|
|
/// Blocks until the queue is empty.
|
|
|
|
void BlockTillEmpty(void)
|
|
|
|
{
|
|
|
|
cCSLock Lock(m_CS);
|
|
|
|
while (!m_Contents.empty())
|
|
|
|
{
|
|
|
|
cCSUnlock Unlock(Lock);
|
|
|
|
m_evtRemoved.Wait();
|
|
|
|
}
|
2013-12-31 10:48:57 -05:00
|
|
|
}
|
2014-01-02 12:43:57 -05:00
|
|
|
|
2014-01-05 09:15:44 -05:00
|
|
|
|
|
|
|
/// Removes all Items from the Queue, calling Delete on each of them.
|
|
|
|
void Clear(void)
|
2013-12-31 10:48:57 -05:00
|
|
|
{
|
|
|
|
cCSLock Lock(m_CS);
|
2014-01-05 09:15:44 -05:00
|
|
|
while (!m_Contents.empty())
|
2013-12-31 10:48:57 -05:00
|
|
|
{
|
2014-01-05 09:15:44 -05:00
|
|
|
Funcs::Delete(m_Contents.front());
|
|
|
|
m_Contents.pop_front();
|
2013-12-31 10:48:57 -05:00
|
|
|
}
|
|
|
|
}
|
2014-01-02 12:43:57 -05:00
|
|
|
|
2014-01-05 09:15:44 -05:00
|
|
|
|
|
|
|
/// Returns the size at time of being called.
|
|
|
|
/// Do not use to determine whether to call DequeueItem(), use TryDequeueItem() instead
|
|
|
|
size_t Size(void)
|
2013-12-31 10:48:57 -05:00
|
|
|
{
|
|
|
|
cCSLock Lock(m_CS);
|
2014-01-05 09:15:44 -05:00
|
|
|
return m_Contents.size();
|
2013-12-31 10:48:57 -05:00
|
|
|
}
|
2014-01-02 12:43:57 -05:00
|
|
|
|
2014-01-05 09:15:44 -05:00
|
|
|
|
|
|
|
/// Removes the item from the queue. If there are multiple such items, only the first one is removed.
|
|
|
|
/// Returns true if the item has been removed, false if no such item found.
|
|
|
|
bool Remove(ItemType a_Item)
|
2013-12-31 10:48:57 -05:00
|
|
|
{
|
|
|
|
cCSLock Lock(m_CS);
|
2014-01-05 09:15:44 -05:00
|
|
|
for (iterator itr = m_Contents.begin(); itr != m_Contents.end(); ++itr)
|
2014-01-03 11:49:14 -05:00
|
|
|
{
|
2014-01-05 09:15:44 -05:00
|
|
|
if ((*itr) == a_Item)
|
|
|
|
{
|
|
|
|
m_Contents.erase(itr);
|
2014-01-03 11:49:14 -05:00
|
|
|
m_evtRemoved.Set();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
2013-12-31 10:48:57 -05:00
|
|
|
}
|
|
|
|
|
2013-12-21 09:43:32 -05:00
|
|
|
private:
|
2014-01-05 09:15:44 -05:00
|
|
|
/// The contents of the queue
|
|
|
|
QueueType m_Contents;
|
|
|
|
|
|
|
|
/// Mutex that protects access to the queue contents
|
2013-12-31 10:48:57 -05:00
|
|
|
cCriticalSection m_CS;
|
2014-01-05 09:15:44 -05:00
|
|
|
|
|
|
|
/// Event that is signalled when an item is added
|
2013-12-31 10:48:57 -05:00
|
|
|
cEvent m_evtAdded;
|
2014-01-05 09:15:44 -05:00
|
|
|
|
|
|
|
/// Event that is signalled when an item is removed (both dequeued or erased)
|
2014-01-02 07:32:55 -05:00
|
|
|
cEvent m_evtRemoved;
|
2013-12-31 10:48:57 -05:00
|
|
|
};
|
2014-01-05 09:15:44 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|