Le code sono le strutture principali per l'immagazzinamento temporaneo dei dati. Meglio conosciute come Buffer implementano un concetto FIFO nella gestione dei dati (first in, first out).
Le code possono essere semplici o doppie: le code semplici sono caratterizzate da un unico punto di inserimento dati e da un unico punto di uscita dei dati. Le code doppie consentono di inserire i dati e prelevare i dati sia nel verso di entrata che nel verso di uscita.
Sebbene il funzionamento basilare sia lo stesso, le code possono essere implementate internamente sia come vettori che come liste collegate. Le code a vettore sono generalmente piu' veloci se occorre scorrerle, ma in genere sono meno flessibili delle liste collegate. Entrambe le versioni sono presenti nella libreria:
TQueue<T> Coda semplice di oggetti (implementata come vettore)
TIQueue<T> Coda semplice di puntatori (implementata come vettore)
TQueueAsDoubleList<T> Coda semplice di oggetti (implementata come doppia lista collegata)
TIQueueAsDoubleList<T> Coda semplice di puntatori (implementata come doppia lista collegata)
TDeque<T> Coda doppia di oggetti (implementata come vettore)
TIDeque<T> Coda doppia di puntatori (implementata come vettore)
TDequeAsDoubleList<t> Coda doppia di oggetti (implementata come doppia lista collegata)
TIDequeAsDoubleList<t> Coda doppia di puntatori (implementata come doppia lista collegata)
TISTQueue<t> Coda semplice di puntatori thread safe (implementata come doppia lista collegata)
E' il classico buffer a dimensione fissa. Il vettore viene dimensionato dal costruttore; e' possibile utilizzare il metodo IsFull() per verificare il riempimento del buffer. Il metodo Peek() consente di ottenere il prossimo elemento della coda senza rimuoverlo.
...
class myClass
{
public:
int var1, var2, var3;
int operator==(const myClass& c) const { return &c == this; }
};
...
...
// fixed size buffer
TIQueue<myClass> myBuffer(10);
...
...
int putInByffer(myClass* ptObj)
{
if(myBuffer.IsFull())
return -1;
myBuffer.Put(ptObj);
return 0;
}
...
...
myClass* getFromBuffer()
{
if(myBuffer.IsEmpty())
return NULL;
return myBuffer.Get();
}
...
...
// this function don't extract elements from queue
myClass* inspectBufferHead()
{
if(myBuffer.IsEmpty())
return NULL;
return myBuffer.Peek();
}
...
...
E' il classico buffer a dimensione illimitata (memoria di sistema permettendo).
...
class myClass
{
public:
int var1, var2, var3;
int operator==(const myClass& c) const { return &c == this; }
};
...
...
// unlimited size buffer
TIQueueAsDoubleList<myClass> myBuffer;
...
...
int putInByffer(myClass* ptObj)
{
myBuffer.Put(ptObj);
return 0;
}
...
...
myClass* getFromBuffer()
{
if(myBuffer.IsEmpty())
return NULL;
return myBuffer.Get();
}
...
...
// this function don't extract elements from queue
myClass* inspectBuffer()
{
if(myBuffer.IsEmpty())
return NULL;
return myBuffer.Peek();
}
...
...
Con una doppia coda e' possibile inserire e prelevare gli elementi da entrambi i lati della coda.
...
class myClass
{
public:
int var1, var2, var3;
int operator==(const myClass& c) const { return &c == this; }
};
...
...
// fixed size buffer
TIDeque<myClass> myBuffer(10);
...
...
int putInByffer(myClass* ptObj)
{
if(myBuffer.IsFull())
return -1;
myBuffer.PutLeft(ptObj);
return 0;
}
...
...
myClass* getFromBuffer()
{
if(myBuffer.IsEmpty())
return NULL;
return myBuffer.GetRight();
}
...
...
// push back element extracted from queue for later processing
int UngetFromByffer(myClass* ptObj)
{
if(myBuffer.IsFull())
return -1;
myBuffer.PutRight(ptObj);
return 0;
}
...
...
Con una doppia coda e' possibile inserire e prelevare gli elementi da entrambi i lati della coda.
...
class myClass
{
public:
int var1, var2, var3;
int operator==(const myClass& c) const { return &c == this; }
};
...
...
// unlimited size buffer
TIDequeAsDoubleList<myClass> myBuffer;
...
...
int putInByffer(myClass* ptObj)
{
myBuffer.PutLeft(ptObj);
return 0;
}
...
...
myClass* getFromBuffer()
{
if(myBuffer.IsEmpty())
return NULL;
return myBuffer.GetRight();
}
...
...
// push back element extracted from queue for later processing
int UngetFromByffer(myClass* ptObj)
{
myBuffer.PutRight(ptObj);
return 0;
}
...
...
Questa coda e' una coda semplice di puntatori a oggetti implementata come doppia lista collegata. La sua particolarita' consiste nell'includere delle istruzioni di sincronizzazione che la rendono thread safe. In particolare le funzioni Get(), Put(), Flush(), Detach(), gli autoiteratori, FirstThat, LastThat, ForEach e il suo iteratore TISTQueueIterator, acquisicono un mutex prima di eseguire qualsiasi operazione.
Oltre al mutex la coda possiede anche un segnalatore di eventi che consente di bloccare un thread quando la coda e' vuota, fino a quando un'altro thread non inserische un oggetto nella coda.
Quando viene creato un iteratore TISTQueueIterator la coda viene bloccata fino alla distruzione dell'oggetto iteratore.
...
class myClass
{
public:
int var1, var2, var3;
int operator==(const myClass& c) const { return &c == this; }
};
...
...
// unlimited size buffer thread safe
TISTQueue<myClass> myBuffer;
...
...
int putInByffer(myClass* ptObj)
{
myBuffer.Put(ptObj);
return 0;
}
...
...
myClass* getFromBuffer()
{
// this thread will be locked until another thread put some object in the queue
myBuffer.LockIfEmpty();
return myBuffer.Get();
}
...
...
int inspectBufferThreadSafe()
{
// when itrBuf will be created it lock the queue until it's destructor will be called
TISTQueueIterator<myClass> itrBuf(myBuffer);
for(itrBuf.Restart() ; itrBuf ; itrBuf++)
{
const myClass& c = itrBuf.Current();
// do somethings
...
}
}
...
...