Implemented Queue.

This commit is contained in:
Marty Kraimer
2010-12-03 15:40:02 -05:00
parent fd36bd47ad
commit e82101b9c6
8 changed files with 504 additions and 30 deletions
+44 -29
View File
@@ -15,8 +15,8 @@ Overview<br />
<p>TODO</p>
<ul>
<li>rename epicsException to exception</li>
<li>Implement pvMisc: BitSetUtil MessageQueue, MultiChoice,Status, and
Queue</li>
<li>implement misc: MessageQueue</li>
<li>Implement pvMisc: BitSetUtil, and Status.</li>
<li>Implement property</li>
</ul>
CONTENTS
@@ -3315,33 +3315,48 @@ private:
<h3 style="text-align: center;">Queue</h3>
<p>This provides a queue which has an immutable capacity, which is specified
when the queue is created. When the queue is full the user code is expected
to keep using the current el;ement until a new free element becomes avalable.
This is used by pvData.monitor.</p>
<pre>NOT IMPLEMENTED</pre>
<p>This provides a queue which has an immutable capacit. When the queue is
full the user code is expected to keep using the current element until a new
free element becomes avalable.</p>
<pre>template &lt;typename T&gt;
class QueueElement : private QueueElementVoid {
public:
QueueElement(T *object) : QueueElementVoid(static_cast&lt;void *&gt;(object)){}
~QueueElement() {}
T *getObject() { return static_cast&lt;T *&gt;(QueueElementVoid::getObject());}
friend class Queue&lt;T&gt;;
};
<p>A queueCreate instance is created via a call like the following:</p>
<pre> QueueCreate&lt;MyObject&gt; queueCreate = new QueueCreate&lt;MyObject&gt;();</pre>
template &lt;typename T&gt;
class Queue : private QueueVoid {
public:
Queue(QueueElement&lt;T&gt; **array,int number)
: QueueVoid((QueueElementVoid**)array,number)
//: QueueVoid(static_cast&lt;QueueElementVoid**&gt;(array),number)
{}
~Queue() {}
void clear() {QueueVoid::clear();}
int getNumberFree() {return QueueVoid::getNumberFree();}
int capacity() {return QueueVoid::capacity();}
QueueElement&lt;T&gt; *getFree() {
return static_cast&lt;QueueElement&lt;T&gt; *&gt;(QueueVoid::getFree());}
void setUsed(QueueElement&lt;T&gt; *queueElement) {
QueueVoid::setUsed(static_cast&lt;QueueElementVoid *&gt;(queueElement));}
QueueElement&lt;T&gt; *getUsed() {
return static_cast&lt;QueueElement&lt;T&gt; *&gt;(QueueVoid::getUsed());}
void releaseUsed(QueueElement&lt;T&gt; *queueElement) {
QueueVoid::releaseUsed(static_cast&lt;QueueElementVoid *&gt;(queueElement));}
};</pre>
<p>Once a queueCreate is available a queue instance is created via code like
the following:</p>
<pre>Queue&lt;MyObject&gt; queue create(MyObject[] myObjects) {
QueueElement&lt;MyObject&gt;[] queueElements = new QueueElement[length];
for(int i=0; i&lt;length; i++) {
QueueElement&lt;MonitorElement&gt; queueElement =
queueCreate.createQueueElement(myObjects[i);
queueElements[i] = queueElement;
}
return queueCreate.create(queueElements);
}</pre>
<p>miscTest/queueTest.cpp provides an example of how to define queueElements
and a queue.</p>
<p>The queue methods are:</p>
<dl>
<dt style="font-family: courier;">clear</dt>
<dd>Make the queue empty.</dd>
<dt style="font-family: courier;">getNumberFree</dt>
<dd>Get the number of fee elements in the queue.</dd>
<dd>Get the number of free elements in the queue.</dd>
<dt style="font-family: courier;">capacity</dt>
<dd>Get the capacity, i.e. the maximun number of elements the queue can
hold.</dd>
@@ -3362,19 +3377,19 @@ the following:</p>
</dl>
<p>A producer calls getFree and setUsed via code like the following:</p>
<pre> MyObject getFree() {
QueueElement&lt;MyObject&gt; queueElement = queue.getFree();
if(queueElement==null) return null;
return queueElement.getObject();
<pre> MyObject *getFree() {
QueueElement&lt;MyObject&gt; *queueElement = queue-&gt;getFree();
if(queueElement==0) return 0;
return queueElement-&gt;getObject();
}</pre>
<p>A consumer calls getUsed and releaseUsed via code like the following:</p>
<pre> while(true) {
QueueElement&lt;MyObject&gt; queueElement = queue.getUsed();
if(queueElement==null) break;
MyObject myObject = queueElement.getObject();
QueueElement&lt;MyObject&gt; *queueElement = queue-&gt;getUsed();
if(queueElement==0) break;
MyObject *myObject = queueElement-&gt;getObject();
// do something with myObject
queue.releaseUsed(queueElement);
queue-&gt;releaseUsed(queueElement);
}</pre>
<hr />
+3
View File
@@ -20,6 +20,8 @@ INC += showConstructDestruct.h
INC += timeStamp.h
INC += timeFunction.h
INC += timer.h
INC += queueVoid.h
INC += queue.h
LIBSRCS += byteBuffer.cpp
LIBSRCS += bitSet.cpp
@@ -33,6 +35,7 @@ LIBSRCS += executor.cpp
LIBSRCS += timeStamp.cpp
LIBSRCS += timeFunction.cpp
LIBSRCS += timer.cpp
LIBSRCS += queueVoid.cpp
LIBRARY=pvMisc
+53
View File
@@ -0,0 +1,53 @@
/* queue.h */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvDataCPP is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
#ifndef QUEUE_H
#define QUEUE_H
#include "queueVoid.h"
namespace epics { namespace pvData {
template <typename T>
class Queue;
template <typename T>
class QueueElement;
template <typename T>
class QueueElement : private QueueElementVoid {
public:
QueueElement(T *object) : QueueElementVoid(static_cast<void *>(object)){}
~QueueElement() {}
T *getObject() { return static_cast<T *>(QueueElementVoid::getObject());}
friend class Queue<T>;
};
template <typename T>
class Queue : private QueueVoid {
public:
Queue(QueueElement<T> **array,int number)
: QueueVoid((QueueElementVoid**)array,number)
//: QueueVoid(static_cast<QueueElementVoid**>(array),number)
{}
~Queue() {}
void clear() {QueueVoid::clear();}
int getNumberFree() {return QueueVoid::getNumberFree();}
int capacity() {return QueueVoid::capacity();}
QueueElement<T> *getFree() {
return static_cast<QueueElement<T> *>(QueueVoid::getFree());}
void setUsed(QueueElement<T> *queueElement) {
QueueVoid::setUsed(static_cast<QueueElementVoid *>(queueElement));}
QueueElement<T> *getUsed() {
return static_cast<QueueElement<T> *>(QueueVoid::getUsed());}
void releaseUsed(QueueElement<T> *queueElement) {
QueueVoid::releaseUsed(static_cast<QueueElementVoid *>(queueElement));}
};
}}
#endif /* QUEUE_H */
+175
View File
@@ -0,0 +1,175 @@
/* queueVoid.cpp */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvDataCPP is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
#include <cstddef>
#include <cstdlib>
#include <cstddef>
#include <string>
#include <cstdio>
#include <stdexcept>
#include "lock.h"
#include "pvType.h"
#include "queueVoid.h"
namespace epics { namespace pvData {
static volatile int64 totalElementConstruct = 0;
static volatile int64 totalElementDestruct = 0;
static volatile int64 totalQueueConstruct = 0;
static volatile int64 totalQueueDestruct = 0;
static Mutex *globalMutex = 0;
static int64 getTotalNodeConstruct()
{
Lock xx(globalMutex);
return totalElementConstruct;
}
static int64 getTotalNodeDestruct()
{
Lock xx(globalMutex);
return totalElementDestruct;
}
static int64 getTotalListConstruct()
{
Lock xx(globalMutex);
return totalQueueConstruct;
}
static int64 getTotalListDestruct()
{
Lock xx(globalMutex);
return totalQueueDestruct;
}
static ConstructDestructCallback *pCDCallbackQueueNode;
static ConstructDestructCallback *pCDCallbackQueue;
static void initPvt()
{
static Mutex mutex = Mutex();
Lock xx(&mutex);
if(globalMutex==0) {
globalMutex = new Mutex();
pCDCallbackQueueNode = new ConstructDestructCallback(
"queueElement",
getTotalNodeConstruct,getTotalNodeDestruct,0);
pCDCallbackQueue = new ConstructDestructCallback(
"queue",
getTotalListConstruct,getTotalListDestruct,0);
}
}
QueueElementVoid::QueueElementVoid(void *object)
: object(object)
{
initPvt();
Lock xx(globalMutex);
totalElementConstruct++;
}
QueueElementVoid::~QueueElementVoid()
{
Lock xx(globalMutex);
totalElementDestruct++;
}
ConstructDestructCallback *QueueElementVoid::getConstructDestructCallback()
{
initPvt();
return pCDCallbackQueueNode;
}
void *QueueElementVoid::getObject() {
return object;
}
QueueVoid::QueueVoid(QueueElementVoidPtrArray array,int number)
: array(array),number(number),
numberFree(number),numberUsed(0),
nextGetFree(0),nextSetUsed(),
nextGetUsed(0),nextReleaseUsed(0)
{
initPvt();
Lock xx(globalMutex);
totalQueueConstruct++;
}
QueueVoid::~QueueVoid()
{
Lock xx(globalMutex);
totalQueueDestruct++;
}
ConstructDestructCallback *QueueVoid::getConstructDestructCallback()
{
initPvt();
return pCDCallbackQueue;
}
void QueueVoid::clear()
{
numberFree = number;
numberUsed = 0;
nextGetFree = 0;
nextSetUsed = 0;
nextGetUsed = 0;
nextReleaseUsed = 0;
}
int QueueVoid::getNumberFree()
{
return numberFree;
}
int QueueVoid::capacity()
{
return number;
}
QueueElementVoid * QueueVoid::getFree()
{
if(numberFree==0) return 0;
numberFree--;
QueueElementVoid *queueElement = array[nextGetFree++];
if(nextGetFree>=number) nextGetFree = 0;
return queueElement;
}
void QueueVoid::setUsed(QueueElementVoid *queueElement)
{
if(queueElement!=array[nextSetUsed++]) {
throw std::logic_error(String("not correcect queueElement"));
}
numberUsed++;
if(nextSetUsed>=number) nextSetUsed = 0;
}
QueueElementVoid * QueueVoid::getUsed()
{
if(numberUsed==0) return 0;
QueueElementVoid *queueElement = array[nextGetUsed++];
if(nextGetUsed>=number) nextGetUsed = 0;
return queueElement;
}
void QueueVoid::releaseUsed(QueueElementVoid *queueElement)
{
if(queueElement!=array[nextReleaseUsed++]) {
throw std::logic_error(String(
"not queueElement returned by last call to getUsed"));
}
if(nextReleaseUsed>=number) nextReleaseUsed = 0;
numberUsed--;
numberFree++;
}
}}
+62
View File
@@ -0,0 +1,62 @@
/* queueVoid.h */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvDataCPP is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
#include "showConstructDestruct.h"
#ifndef QUEUEVOID_H
#define QUEUEVOID_H
namespace epics { namespace pvData {
class QueueVoid;
class QueueElementVoid;
typedef QueueElementVoid * QueueElementVoidPtr;
typedef QueueElementVoidPtr * QueueElementVoidPtrArray;
class QueueElementVoid {
public:
~QueueElementVoid();
static ConstructDestructCallback *getConstructDestructCallback();
void *getObject();
protected:
QueueElementVoid(void *object);
private:
void *object;
friend class QueueVoid;
};
typedef class QueueElementVoid * QueueElementVoidArray;
class QueueVoid {
public:
~QueueVoid();
static ConstructDestructCallback *getConstructDestructCallback();
void clear();
int getNumberFree();
int capacity();
QueueElementVoid *getFree();
void setUsed(QueueElementVoid *queueElement);
QueueElementVoid *getUsed();
void releaseUsed(QueueElementVoid *queueElement);
protected:
QueueVoid(QueueElementVoidPtrArray array,int number);
private:
friend class QueueElementVoid;
QueueElementVoidPtrArray array;
int number;
int numberFree;
int numberUsed;
int nextGetFree;
int nextSetUsed;
int nextGetUsed;
int nextReleaseUsed;
};
}}
#endif /* QUEUEVOID_H */
+4
View File
@@ -10,6 +10,10 @@ PROD_HOST += testLinkedList
testLinkedList_SRCS += testLinkedList.cpp
testLinkedList_LIBS += pvMisc Com
PROD_HOST += testQueue
testQueue_SRCS += testQueue.cpp
testQueue_LIBS += pvMisc Com
PROD_HOST += testThread
testThread_SRCS += testThread.cpp
testThread_LIBS += pvMisc Com
+162
View File
@@ -0,0 +1,162 @@
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvDataCPP is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/*
* testQueue.cpp
*
* Created on: 2010.12
* Author: Marty Kraimer
*/
#include <cstddef>
#include <cstdlib>
#include <cstddef>
#include <string>
#include <cstdio>
#include <epicsAssert.h>
#include "lock.h"
#include "timeStamp.h"
#include "queue.h"
#include "showConstructDestruct.h"
#include "event.h"
#include "thread.h"
#include "executor.h"
using namespace epics::pvData;
struct Data {
int a;
int b;
};
static int numElements = 5;
typedef QueueElement<Data> DataElement;
typedef Queue<Data> DataQueue;
class Sink : public Runnable {
public:
Sink(DataQueue *queue,FILE *auxfd);
~Sink();
void stop();
void look();
virtual void run();
private:
DataQueue *queue;
FILE *auxfd;
bool isStopped;
Event *wait;
Event *stopped;
Event *waitReturn;
Event *waitEmpty;
Thread *thread;
};
Sink::Sink(DataQueue *queue,FILE *auxfd)
: queue(queue),
auxfd(auxfd),
isStopped(false),
wait(new Event()),
stopped(new Event()),
waitReturn(new Event()),
waitEmpty(new Event()),
thread(new Thread(String("sink"),middlePriority,this))
{
}
Sink::~Sink() {
delete thread;
delete waitEmpty;
delete waitReturn;
delete stopped;
delete wait;
}
void Sink::stop()
{
isStopped = true;
wait->signal();
stopped->wait();
}
void Sink::look()
{
wait->signal();
waitEmpty->wait();
}
void Sink::run()
{
while(!isStopped) {
wait->wait();
if(isStopped) break;
while(true) {
DataElement *element = queue->getUsed();
if(element==0) {
waitEmpty->signal();
break;
}
Data *data = element->getObject();
fprintf(auxfd," sink a %d b %d\n",data->a,data->b);
queue->releaseUsed(element);
}
}
stopped->signal();
}
static void testBasic(FILE * fd,FILE *auxfd ) {
Data dataArray[numElements];
DataElement *array[numElements];
for(int i=0; i<numElements; i++) {
array[i] = new DataElement(&dataArray[i]);
dataArray[i].a = i;
dataArray[i].b = i*10;
}
DataQueue *queue = new DataQueue(array,numElements);
Sink *sink = new Sink(queue,auxfd);
while(true) {
DataElement *element = queue->getFree();
if(element==0) break;
Data *data = element->getObject();
fprintf(auxfd,"source a %d b %d\n",data->a,data->b);
queue->setUsed(element);
}
sink->look();
// now alternate
for(int i=0; i<numElements; i++) {
DataElement *element = queue->getFree();
assert(element!=0);
Data *data = element->getObject();
fprintf(auxfd,"source a %d b %d\n",data->a,data->b);
queue->setUsed(element);
sink->look();
}
sink->stop();
delete sink;
delete queue;
for(int i=0; i<numElements; i++) delete array[i];
}
int main(int argc, char *argv[]) {
char *fileName = 0;
if(argc>1) fileName = argv[1];
FILE * fd = stdout;
if(fileName!=0 && fileName[0]!=0) {
fd = fopen(fileName,"w+");
}
char *auxFileName = 0;
if(argc>2) auxFileName = argv[2];
FILE *auxfd = stdout;
if(auxFileName!=0 && auxFileName[0]!=0) {
auxfd = fopen(auxFileName,"w+");
}
testBasic(fd,auxfd);
getShowConstructDestruct()->constuctDestructTotals(fd);
return (0);
}
+1 -1
View File
@@ -57,7 +57,7 @@ typedef int32 * IntArray;
typedef int64 * LongArray;
typedef float * FloatArray;
typedef double * DoubleArray;
//typedef String * StringArray; alreadt defined in pvType.h
//typedef String * StringArray; already defined in pvType.h
class PVAuxInfo : private NoDefaultMethods {
public: