Reputation: 27673
How do I achieve a background task that waits for events to be raised by other processes, similar to how a Winforms Form
does "nothing" until an event is raised? I would like to know how to do this in two cases:
(But an answer to one would be appreciated as well, of course.)
The specific type of usage I'm facing now is to have this task process a queue (FIFO) and when the queue is empty - wait. But please don't restrict your answers to that as I'm interested in a general answer.
I've used the terms task
and process
, but perhaps the term thread
should be used. Please feel free to correct me if I'm wrong.
EDIT
I'm looking for some built-in mechanism, rather than implementing a "message pump". And preferably, built-in to .net, not a library that has to be installed.
Upvotes: 0
Views: 1371
Reputation: 6379
Within an application (not across apps) - a simple queue pattern will do it, you can use a thread signalling mechanism. Here is a simple example:
Declare a thread-safe collection to store your command, a task (thread pool thread, effectively) to process the queue, a signal trigger - and a flag to allow exiting later:
private ConcurrentQueue<CommandObject> _queueCommands
private Task _queueProcessorTask;
private AutoResetEvent _trigger;
private bool _isRunning;
The code to initialise and kick off the queue processor:
_queueCommands = new ConcurrentQueue<CommandObject>();
_queueProcessorTask = new Task(ProcessQueue);
_trigger = new AutoResetEvent(false);
_isRunning = true;
_queueProcessorTask.Start();
Your queue processor itself will look like something this:
while (_isRunning)
{
if (_isRunning && _queueCommands .Count != 0)
{
if (_queueCommands.TryDequeue(out command))
{
// do the job, this is FIFO
}
}
// you wanna wait here, but only if there's nothing new to do
if (_isRunning && _queueCommands.Count == 0)
{
_trigger.WaitOne(10000, false);
}
}
And some code to add requests to the queue:
_queueCommands.Enqueue(newCommand);
_trigger.Set(); // this is the bit which does your event / signal to spark queue processor into life
There is also a collection called BlockingCollection that can do the above with the signal part intrinsic, but I like to show this verbose version so you know what's going on.
ADDED: With the code above we're basically notifying a dedicated thread that it has a message / command to process - so you're "message pump" if you will. The blocking collection does this in less steps but you still have to add something to the collection to "pump" that message!
Upvotes: 1
Reputation: 13224
Your question is very broad and as such a lot of good answers are possible. It really depends on what you are trying to achieve. Many options exist and you just need to carefully look at your requirements and determine what fits best.
The basic pattern that would appear to apply in most cases is that of queued event or message handling.
I will list a few available "out of the box" solutions that address different types of needs, without trying to make this an exhaustive list.
There are several "precooked" solutions available that for example could fit if you are doing eventing / messaging across multiple processes.
If you require some form of durable messaging, you could look at one of several message bus implementations, such as e.g. NServiceBus, Kafka, ...
If your messaging needs to be fast but does not require durability, then something like 0mq that supports multiple messaging patterns could be useful, if you want to do this across .NET web apps, you may want to have a look at SignalR.
If you are looking to do any type of complex event processing, or you want to have a permanent memory of the events and do "computatations", such as aggregation or other types of projections over a series of events, you could have a look at the EventStore project.
If you want to do something simple, like get notifications when data in your database has changed, you could look into specific change notification services / trigger analogs for your specific type database (e.g. RavenDB's changes API).
If you need to perform (non-durable) messaging between threads in a single process, the two most complete "prebaked" building blocks available to you are the
TPL Dataflow Allow to set up specific data processing pipelines, with several buffering and transformation options (think pipes and filters).
Reactive extensions Specifically intended to build non-durable asynchronous event processing, composing and transforming events using observable sequences and LINQ-style query operators.
If your needs are far simpler than what they offer, you could build your own, taking into account the basic type of tried and tested patterns that are used in the solutions already mentioned.
Upvotes: 0