This is the 5th of several posts about TEAM.Common, a set of functionality I use in every project and that I'd like to share. The index is here:
http://rodolfograve.blogspot.com/2010/09/teamcommons-introduction.html
In TEAM.Common.Threading you can find these abstractions:
WorkerThread
A thread running a task in an "infinite" loop, until some other thread asks it to stop.
This is a very basic piece I use it all the time for implementing services and it's also the foundation for the "advanced" features.
public abstract class WorkerThread
{
Exception Error { get; }
void ForceStop();
bool IsStopped { get; }
void Start();
void Stop();
event EventHandler<System.ComponentModel.RunWorkerCompletedEventArgs> Stopped;
}
ProducerConsumersProcess
My approach to parallelization was to use the one producer -> several consumers technique:
You must create an instance of this class passing an instance of IProducer and a list of IConsumerWorker.
public class ProducerConsumersProcess<T>
{
int ConsumedItemsCount { get; }
int ProducedItemsCount { get; }
void Start();
}
With a very simple interface, ProducerConsumersProcess<T> coordinates the producer and the consumers using a buffer (an
InProcessTransport, see
next post) and handling a lot of edge cases and exceptions.
IProducer
public interface IProducer<T>
{
T ProduceOne();
bool HasFinished();
}
IConsumerWorker<T>
public interface IConsumerWorker<T>
{
event EventHandler<RunWorkerCompletedEventArgs> Stopped;
void Start(IReceivingTransport receivingTransport);
void StopWhenStarved();
void InterruptExecution();
bool IsStopped { get; }
int ProcessedItemsCount { get; }
Exception Error { get; }
string Id { get; }
}
These are the foundations for all the good stuff. The rest are classes that help in the most common cases:
DelegatedProducer<T>
Just pass two delegates:
public DelegatedProducer(Func<T> producerDelegate, Func<bool> hasFinishedDelegate)
Combine it with lambda expressions and you have a very flexible and expressive syntax.
EnumeratorProducer<T>
Just pass an IEnumerable:
public EnumeratorProducer(IEnumerable<T> enumerableSource)
Combine it with the
yield operator and/or lambda expressions and again, you have a very flexible and expressive syntax.
EnumeratorProducer<T>
Just pass an IEnumerable:
public DelegatedConsumerWorker(string id, TimeSpan starvationTimeOut, int processedItemsCountMonitorizationStep, Action<T> consumerDelegate)
You know what comes now: mix it with lambda expressions and...
Remember, you can get all this code for free at bitbucket:
http://bitbucket.org/rodolfograve/team.commons/overview
Check it out to get ideas, or simply use it as it is. It's working out for me and my team.