Skip to content

Instantly share code, notes, and snippets.

@StonedXander
Created December 22, 2011 10:54
Show Gist options
  • Save StonedXander/1509910 to your computer and use it in GitHub Desktop.
Save StonedXander/1509910 to your computer and use it in GitHub Desktop.
Simple Consumer
/**
* Consumer generic class.
* Delegates the following services:
* - evaluate : returns if the run method must be exited.
* - process : process the item buffer.
* - compute : compute the internal state.
* The 'target' concept must implement the method:
* bool swap(I **, unsigned *);
* and the constructor :
* T::T(K *);
* Hence, delegate and target shares the same initialisation context.
* It provides a working buffer.
*/
template <typename T, typename I, typename D, typename K> class Consumer {
public:
/**
* Constructor.
*/
Consumer(K *context) : delegate(context), target(context), buffer(0), size(0) {}
/**
* Entry point.
*/
void run() {
while(delegate.evaluate()) {
if(target.swap(&buffer, &size)) {
delegate.process(buffer, size);
}
delegate.compute();
}
}
private:
D delegate;
T target;
I *buffer;
unsigned int size;
};
/**
* Here is the provider class, maintaining the double buffered list.
* By the way, it will also need a delegation object, taking the exact
* same context in constructor parameters.
*/
template <typename I, typename K> class Provider {
public:
/**
* Constructor.
* The context strikes back, but it's stronger now !
*/
Provider(K *context) {
// Guess who will have a parametrized method which the following prototype ?
// template <typename I> void initialize(I **buffer);
context->initialize(&buffer);
context->initialize(&unused);
size = 0;
// TODO Initialize mutexes
}
bool swap(I **bf, unsigned int *sz) {
bool result = size != 0; // Not thread safe. In fact, it's not a problem.
// If we miss it now, we'll catch it later. It just implies a silent latency.
if(result) { // Grrr ... Branches ...
lock(); // Mutex call.
*bf = buffer;
*sz = size;
size = 0;
buffer = unused;
unused = *bf;
unlock(); // Mutex call.
}
return result;
}
private:
I *buffer;
I *unused;
unsigned int size;
};
@StonedXander
Copy link
Author

The 'target' should be part of the consumer. In this case, we'll be sure that no concurrent call to the 'swap' method will be done.

@StonedXander
Copy link
Author

By now, thre's an obvious spot of optimisation. Run method calls four methods !! 'evaluate' can be inlined. There's two branches. Now, everything will depend on the target. If it's well implemented, we can expected a tail-call optimisation. It will be interesting to check generated assembly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment