#include <pipeline.h>
Inheritance diagram for rpa::pipe_circular< Container, CondVar >:
Public Types | |
typedef pipebase_t::iterator | iterator |
typedef pipebase_t::mutex_type | mutex_type |
typedef pipebase_t::value_type | value_type |
typedef range_step< pipe_circular, pipe_circular > | range_step_type |
typedef pipe_itr< value_type, reader > | sync_iter |
Public Member Functions | |
void | check (void) const |
If Not rd_before_wr, then distance will never stops. | |
pipe_circular (mutex_type *mtxPtr, size_t maxNb) | |
template<class Iter> | |
pipe_circular (mutex_type *mtxPtr, Iter begIter, Iter endIter, bool shutFlag=true) | |
pipe_circular (mutex_type *mtxPtr, const Container &aCont, bool shutFlag=true) | |
~pipe_circular () | |
QUESTION: FOR WHICH REASON ALL WRITERS HAVE FINISHED ? | |
void | push_back (const value_type &aV) |
template<class IterIn> | |
void | append (IterIn itBeg, IterIn itEnd, size_t szReserve) |
bool | data_ready (void) const |
Tells whether there is data to read in the pipeline. | |
sync_iter | begin (void) |
These two iterators can be used into algorithm of std. | |
sync_iter | end (void) |
range_step_type | build_range (size_t nbSteps, chunk_t aCM=chunk_t()) |
Range creation is protected by a mutex, because its reads internal data. | |
Private Types | |
typedef pipebase< Container, CondVar > | pipebase_t |
Private Member Functions | |
GccNoFriend (private) | |
GccNoFriend (private) | |
void | slice_del (slice *slicePtr) |
Removes this slice from the list of slices being used by sub-threads. | |
GccNoFriend (private) | |
void | init (bool aFull) |
void | wait_for_writing (void) |
Used by push_back and append. The mutex must be locked. | |
void | setup_rd_and_wr_iters (void) |
This must be done after insertions. Used by push_back and append. | |
Private Attributes | |
CondVar | _condNotFull |
Can use any conditions as long as they are based on the same mutex. | |
GccNoFriend(private) iterator | _it_wr |
size_t | _nbWaitWr |
slice * | _slice_first |
slice * | _slice_last |
Friends | |
class | range_step< pipe_circular< Container, CondVar >,pipe_circular< Container, CondVar > > |
This does not work with gcc 3.x.y. Find GccNoFriend. | |
Classes | |
class | reader |
Template param for pipe_itr, an iterator in pipelines'underlying container. More... | |
class | slice |
typedef pipebase_t::iterator rpa::pipe_circular< Container, CondVar >::iterator |
Reimplemented from rpa::pipebase< Container, CondVar >.
typedef pipebase_t::mutex_type rpa::pipe_circular< Container, CondVar >::mutex_type |
Reimplemented from rpa::pipebase< Container, CondVar >.
typedef pipebase< Container, CondVar > rpa::pipe_circular< Container, CondVar >::pipebase_t [private] |
typedef range_step< pipe_circular, pipe_circular > rpa::pipe_circular< Container, CondVar >::range_step_type |
This range can be used into any algorithm of this library. It is synchronized with the internal mutex of the container.
typedef pipe_itr< value_type, reader > rpa::pipe_circular< Container, CondVar >::sync_iter |
typedef pipebase_t::value_type rpa::pipe_circular< Container, CondVar >::value_type |
rpa::pipe_circular< Container, CondVar >::pipe_circular | ( | mutex_type * | mtxPtr, | |
size_t | maxNb | |||
) | [inline] |
Sets the maximum size of the container. The buffer is not full at the beginning. We could do a lazy-resizing, only when it is necessary, but there is no point to wait : If a given size is necessary, why not resizing now ? More: By setting the right size immediately, we ensure that the iterators are always valid. On the other hand, the real shame of it is that we must always pay the price of a full allocation even for a couple of data. (This is also true for output buffers obuf_iterator). To compensate this, a buffer can be reused, once allocated.
rpa::pipe_circular< Container, CondVar >::pipe_circular | ( | mutex_type * | mtxPtr, | |
Iter | begIter, | |||
Iter | endIter, | |||
bool | shutFlag = true | |||
) | [inline] |
Initialize the buffer with a content. At the beginning, the buffer is considered as full.
rpa::pipe_circular< Container, CondVar >::pipe_circular | ( | mutex_type * | mtxPtr, | |
const Container & | aCont, | |||
bool | shutFlag = true | |||
) | [inline] |
Initialize the buffer with a content. At the beginning, the buffer is considered as full.
rpa::pipe_circular< Container, CondVar >::~pipe_circular | ( | ) | [inline] |
QUESTION: FOR WHICH REASON ALL WRITERS HAVE FINISHED ?
void rpa::pipe_circular< Container, CondVar >::append | ( | IterIn | itBeg, | |
IterIn | itEnd, | |||
size_t | szReserve | |||
) | [inline] |
Copies piece by piece, until the buffer is full, then waits until it gets read by other threads, then writes again. Uses most of the code of 'pipe_circularpush_back'.
Theoretically, it would be faster to wait until much space is freed: This would avoid many cond_wait. This is not possible in the general case: The most expensive is to go back to the kernel anyway.
Now we can copy as much element as we want until the writing iterator reaches the end of the buffer. We could specialize this copy if both types of iterators are random_access. The idea would be to count how many elements can be copied in one go, and then use std::copy_n.
We have inserted many elements, so we must notify reading threads:
sync_iter rpa::pipe_circular< Container, CondVar >::begin | ( | void | ) | [inline] |
These two iterators can be used into algorithm of std.
Reimplemented from rpa::pipe_container< Container >.
range_step_type rpa::pipe_circular< Container, CondVar >::build_range | ( | size_t | nbSteps, | |
chunk_t | aCM = chunk_t() | |||
) | [inline] |
Range creation is protected by a mutex, because its reads internal data.
void rpa::pipe_circular< Container, CondVar >::check | ( | void | ) | const [inline] |
If Not rd_before_wr, then distance will never stops.
Casts to the base class, in order to use its check method.
Reimplemented from rpa::pipebase< Container, CondVar >.
bool rpa::pipe_circular< Container, CondVar >::data_ready | ( | void | ) | const [inline] |
Tells whether there is data to read in the pipeline.
'full' means: (pipebase_t::_it_rd == _it_wr) && (false == _rd_before_wr) So, we add another check to avoid the ambiguity with emptiness.
sync_iter rpa::pipe_circular< Container, CondVar >::end | ( | void | ) | [inline] |
Reimplemented from rpa::pipe_container< Container >.
rpa::pipe_circular< Container, CondVar >::GccNoFriend | ( | private | ) | [inline, private] |
When a slice is just created with a 'chop', or is chopped again, the end of the slice becomes the 'Rd' of the slice, that is, the first place to read from. The mutex stays locked between the lock and this method. full = (pipebase_t::_it_rd == _it_wr) && (false == _rd_before_wr);
rpa::pipe_circular< Container, CondVar >::GccNoFriend | ( | private | ) | [inline, private] |
rpa::pipe_circular< Container, CondVar >::GccNoFriend | ( | private | ) | [inline, private] |
void rpa::pipe_circular< Container, CondVar >::init | ( | bool | aFull | ) | [inline, private] |
The flag indicates whether the container is full at the beginning. The flag _rd_before_wr does not take the same value depending if the container is true or not. If the two iterators rd et wr are on the same position, if there is nothing in the container, rd_before_wr is true, otherwise false.
It points in fact at the end.
void rpa::pipe_circular< Container, CondVar >::push_back | ( | const value_type & | aV | ) | [inline] |
This is compatible with std::back_inserter. If _slice_first is not NULL, it means that there is at least one slice which is currently used by a thread. If its beginning is at the place to write, we cannot change content which is being read now. On the other hand, the insertion itself cannot invalidate iterators because, in a circular buffer, all elements are already allocated.
This notifies only one thread because only one element is inserted.
void rpa::pipe_circular< Container, CondVar >::setup_rd_and_wr_iters | ( | void | ) | [inline, private] |
This must be done after insertions. Used by push_back and append.
This is done even if _it_rd is at the beginning. Maybe the pipe is now full.
_rd cannot be before _wr except if they are at the same place. If this is so, and if the container is empty, then exceptionnaly set to false. This is because the information of full+before+(rd==wr) is redundant.
At this stage, the pipeline is OK.
void rpa::pipe_circular< Container, CondVar >::slice_del | ( | slice * | slicePtr | ) | [inline, private] |
Removes this slice from the list of slices being used by sub-threads.
If this slice is the first of the list, it may be blocking writes if there is no more space. This must be guarded by the pipeline's mutex.
This tests first the presence at the beginning rather than the end, because there is a specific processing: If the slice begins at the writing position, then it must unblock threads which are waiting to write in the buffer.
Now the list is empty.
Maybe this slice is blocking some writing thread. We wake up all the threads which are waiting to write in the pipeline.
Just removing the slice from the list. After that, the list cannot be empty, otherwise _first == slicePtr (1st test).
void rpa::pipe_circular< Container, CondVar >::wait_for_writing | ( | void | ) | [inline, private] |
Used by push_back and append. The mutex must be locked.
It returns when there is room to write new data.
A new thread is waiting to write.
If the pipe is full, it is impossible to write in it. If it is not full, but the first 'running' slice is sitting where we need to write data, we must wait too. The running slices are in a list sorted by order of creation, and therefore follows the order of writing and reading in the circular pipe.
The thread has finished to wait for writing.
friend class range_step< pipe_circular< Container, CondVar >,pipe_circular< Container, CondVar > > [friend] |
This does not work with gcc 3.x.y. Find GccNoFriend.
CondVar rpa::pipe_circular< Container, CondVar >::_condNotFull [private] |
Can use any conditions as long as they are based on the same mutex.
GccNoFriend (private) iterator rpa::pipe_circular< Container, CondVar >::_it_wr [private] |
This points on the next free place to write an element, or on the reading iterator if the pipeline is full. If it is full, both pointers are equal and the flag _rd_before is false.
size_t rpa::pipe_circular< Container, CondVar >::_nbWaitWr [private] |
This is the number of threads currently waiting to write data. It is protected by condNotFull and is used for notifying when more than one thread may be woken up, when a full slice is released. When freeing a single element (With a single read), only one thread is woken up.
slice* rpa::pipe_circular< Container, CondVar >::_slice_first [private] |
slice * rpa::pipe_circular< Container, CondVar >::_slice_last [private] |