Implemented Queue.
This commit is contained in:
@@ -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 <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>;
|
||||
};
|
||||
|
||||
<p>A queueCreate instance is created via a call like the following:</p>
|
||||
<pre> QueueCreate<MyObject> queueCreate = new QueueCreate<MyObject>();</pre>
|
||||
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));}
|
||||
};</pre>
|
||||
|
||||
<p>Once a queueCreate is available a queue instance is created via code like
|
||||
the following:</p>
|
||||
<pre>Queue<MyObject> queue create(MyObject[] myObjects) {
|
||||
QueueElement<MyObject>[] queueElements = new QueueElement[length];
|
||||
for(int i=0; i<length; i++) {
|
||||
QueueElement<MonitorElement> 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<MyObject> queueElement = queue.getFree();
|
||||
if(queueElement==null) return null;
|
||||
return queueElement.getObject();
|
||||
<pre> MyObject *getFree() {
|
||||
QueueElement<MyObject> *queueElement = queue->getFree();
|
||||
if(queueElement==0) return 0;
|
||||
return queueElement->getObject();
|
||||
}</pre>
|
||||
|
||||
<p>A consumer calls getUsed and releaseUsed via code like the following:</p>
|
||||
<pre> while(true) {
|
||||
QueueElement<MyObject> queueElement = queue.getUsed();
|
||||
if(queueElement==null) break;
|
||||
MyObject myObject = queueElement.getObject();
|
||||
QueueElement<MyObject> *queueElement = queue->getUsed();
|
||||
if(queueElement==0) break;
|
||||
MyObject *myObject = queueElement->getObject();
|
||||
// do something with myObject
|
||||
queue.releaseUsed(queueElement);
|
||||
queue->releaseUsed(queueElement);
|
||||
}</pre>
|
||||
<hr />
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
|
||||
@@ -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++;
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -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 */
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user