Michael Crosby


Multithreading in C#

From my point of view the reason why we create multithreaded applications is so the user experience does not suffer. We have operations that need completed but running these on the main thread will block the UI and piss off our users.

Most of the operations have some similarities. Atleast for myself, the most common use case is the user requests information, we process it, then display the results back. That is the most common use that I use background threads for. When we display these results back, we need to write code that is executed on the Main thread to update the UI.

Working with delegates, callbacks, and IAsyncResults suck. They cause you to write more methods and change your code. There should be an easy way to write code normally and have all the benefits of async programming. That is what I try to accomplish in my WPF MVVM-Async framework. It allows you to write code normally and create multithreading applications with lambdas.

MVVM-Async

So first thing that you need to do to take advantage of the framework is to make your ViewModel inherit from ViewModelBase and pass it a type for the model. By doing this you automatically get access to the Model object.

public class EditorViewModel : ViewModelBase<EditorModel>
...
this.Model.EditorModelProperties...

Async

Now just code and when you want to dispatch a process in a background thread call DispatchAsync() and pass it a lambda.

DispatchAsync(()=> {

    int i = 0;
    bla bla bla

});

The framework will automatically spawn a new thread and execute whatever you placed inside the lambda on that thread. You can even call another method and pass any variables to it. By using lambdas you stay in the scope of the method calling DispatchAsync.

DispatchAsync(() => {

    SomeOtherFunc(name, date, age);

});

Updating the UI

So now we have this lambda executing on a background thread and processing data. We need to take that data and update our UI.

DispatchAsync(() => {

    string fullName = GetFullName(first, last);

    MyViewsTextBoxDataSource = fullName;

});

This is very simple but you get the point. If we were to try to set one of our view's controls from a background thread we would throw an exception because you can only set Controls on the thread that created it. So without using callbacks we can do this easily with the framework.

DispatchAsync(() => {

    string fullName = GetFullName(first, last);

    DispatchMainAsync(() => {

        MyViewsTextBoxDataSource = fullName;

    });

});

How hard was that? If we want to dispatch a lambda to the main thread that updates the UI, we can write it inline, with all our variables in scope, and have that code executed on the main thread. No exceptions.

Easy, simple, and you don't have to have callbacks or other crap to mess with. If you do want a callback when a thread has finished executing the framework does support this.

void DispatchAsyncWithCallback(action, callback);
void DispatchAsyncWithCallback(action, callback, whereTo);

The whereTo tells the framework on what thread do you want the callback executed one. Call me back on a background thread or call me back on the main thread.

DispatchAsyncWithCallback(() => {

    doSomeStuff();

}, () => {

    doSomeStuffOnTheCallback();

}, DispatchOn.Main); //Dispatch the callback on the main thread.

It's all done inline.

Queues

There is also support of Queues. You can load up a DispatchQueue with tasks and invoke the entire queue.

void AddQueue(DispatchQueue queue);
void InvokeQueue(string name);
void ProcessAllQueues();

Timed Execution

You can also tell the framework when to dispatch a thread.

DispatchIn(() => { somethingToDo(); }, "5min");

Or at a specific time.

DateTime someTime;
DispatchAt(() => { somethingToDo(); }, someTime);

Final

I am still working on this and will be releasing the code soon after CodeAssistant is complete. CodeAssistant is using this framework.

comments powered by Disqus