4

According to MSDN, Dispatcher provides services for managing the queue of work items for a thread.

A simple question. I want to use Dispatcher just for that: as a queue of work items (posted via Dispatcher.BeginInvoke) which my background thread will serve in a serial manner.

I don't want to make this thread an STA thread and I don't need to pump Windows messages on it. There will be no UI on this thread.

Is it a legitimate way of using Dispatcher?

avo
  • 10,101
  • 13
  • 53
  • 81
  • 1
    No. `System.Windows.Threading.Dispatcher` is a WPF-specific construct and should not be used for background processing. You're looking for the TPL. – Federico Berasategui Feb 22 '14 at 02:26
  • It certainly sounds like it from the description of the class. Do you really want to use the same thread for every work item though? Normally it would be more desirable to just queue the work items and let the system decide what thread to execute them on. As far as I can see, you're going to have to use the CurrentDispatcher property on that thread to get the Dispatcher for that thread, so that will have to be done on the thread first, but you'll also have to ensure that that thread doesn't terminate before you queue these work items. – jmcilhinney Feb 22 '14 at 02:28
  • @HighCore, TPL doesn't have a built-in feature like this. The closest one is [`StaTaskScheduler`](http://blogs.msdn.com/b/pfxteam/archive/2010/04/07/9990421.aspx) by Stephen Toub. – avo Feb 22 '14 at 04:00
  • @jmcilhinney, there're cases when work items needs to be serialized, for example [this](http://stackoverflow.com/questions/21211998/stataskscheduler-and-sta-thread-message-pumping). I just want to know what tools I have in my disposal if I need to deal with this again. – avo Feb 22 '14 at 04:03
  • @avo, quite so, but I'd expect that such cases would be in the minority, which is why I asked. Another option would be to simply queue up a bunch of delegates yourself and then start a thread that dequeues those delegates in a loop, terminating or being returned to the pool when the queue is empty. – jmcilhinney Feb 22 '14 at 04:10
  • 1
    @avo, so what's wrong with `StaTaskScheduler`? If you don't need a pool of threads, use something like [`SerialTaskScheduler`](http://stackoverflow.com/a/21645679/1768303) from here. I've already [answered](http://stackoverflow.com/a/18183871/1768303) a related question of yours, `Dispatcher.Run` **does pump windows messages**, so it's probably not what you're looking for. This is also related: http://stackoverflow.com/a/21949767/1768303 – noseratio Feb 22 '14 at 05:28

2 Answers2

5

Is it a legitimate way of using Dispatcher?

You could use a secondary thread with a Dispatcher, but it's rather uncommon. This is usually done so that different parts of the UI run on different UI threads. A dispatcher thread will process Windows messages, and must be STA. Also, technically speaking the processing isn't strictly FIFO since dispatched items are queued with a priority.

That said, even though it wasn't designed to be used without a UI, you could use it that way.

Alternatives:

1) AsyncContextThread is a simple thread with a work queue from my AsyncEx NuGet library:

private readonly AsyncContextThread _thread = new AsyncContextThread();
...
_thread.Factory.StartNew(() => { ... });

The AsyncContextThread type provides a SynchronizationContext for the code it runs, so async continuations will resume on the same thread by default.

2) If it only matters that the requests are processed serially, and doesn't actually matter which thread they run on, then you can use a task scheduler to instruct the thread pool to run your requests one at a time, as such:

private readonly TaskFactory _factory = new TaskFactory(
    new ConcurrentExclusiveSchedulerPair().ExclusiveScheduler);
_factory.StartNew(() => { ... });
Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
3

Short answer:

If you need to actually do work with Dispatcher runtime components, such as System.Windows.Media.Imaging, then I have an answer for you. If you're not using Dispatcher runtime components then don't even consider using the Dispatcher runtime. Use the Task Parallel Library (TPL) instead.

Long answer:

I've built and use this DispatcherTaskScheduler implementation in high volume production services. You can configure it with as many threads as you'd like it to have a pool of (default is number of cores) and it will take care of spinning up those threads, initializing them with the Dispatcher runtime and then queuing and dispatching work to them. Works with great with TPL, TPL DataFlow, SynchronizationContext style programming (e.g. async/await), etc.

Basic usage looks something like this:

Task.Factory.StartNew(() =>
{
   // Do anything you want with Dispatcher components here
},
CancellationToken.None,
TaskCreationOptions.None,
DispatcherTaskFactory.Default);

If you configure your own instance (e.g. you want more threads) then just replace DispatcherTaskFactory.Default with your instance instead. My advice is to not configure more threads than cores (just use the Default instance) and make sure you try to only do Dispatcher runtime work on these threads.

As I mentioned, I use this implementation in several parts of our software system related to image processing that are core to our business and endure high volume loads and it's proven absolutely bullet proof for us.

Finally, the disclaimer: Microsoft doesn't really support the Dispatcher runtime being used like this.

Drew Marsh
  • 33,111
  • 3
  • 82
  • 100