Cross-Threaded Calls in .NET!

Now-a-days everybody has a Multi-core environment and you are required to code threads and/or multiple processes to be scalable and fully utilize the current hardware systems. And yes, it also proves that you are a good coder and are keeping up and committed to development of multi-threaded, multi-core applications. Now, now, I am talking a bit silly since threading is a concept existing since the dawn of computing. It was pretty much explicit and you can feel the power when you code in C or C++. But when it comes to high level frameworks and languages like .NET, C#, VB.NET, etc. the simplicity of using threads might become a big problem and lead to no understanding of how things actually operate. Of course execution context is something to learn about and a good programmer should always be aware of what execution context his/her thread/process is executing in otherwise he/she would find himself/herself in a lot of problems related to thread synchronization, deadlocks, etc.

I am still pretty new to C# and decided to use threads in MultiDoc2HTML v0.2 (v0.1 is available on Multiple HTMLs into a Single Document – MultiDoc2HTML v0.1). The logic as explained in other articles on the blog is quite serial and repetitive i.e. one cannot use multiple threads to do the job since each and every operation has to be done one after the other. In short, it is a batch operation which is not a direct candidate for multi-threading. But still there are ways to attack the problem and use threads especially for this particular logic. Not to deviate from the topic at hand, I will write about that in some other post.

For the time being, I wanted to do the batch execution in a separate thread (I could have used background thread for that but I think thread is more clean then background thread). Anyways, I will create one more version with background thread later on. But for the time being, I created a separate worker thread to do the batch processing and the main thread keeps updating the UI properly i.e. show the progress bar. It uses a timer tick event to do it i.e. Progress bar is not a visual indication of amount of work done/left. It is just there to tell the user that the worker thread is doing its work. The worker thread does the batch execution and generates an event to notify the main thread when all the processing is done. I would like to put the progress bar to the maximum value to be esthetically correct since having it midway would not be a justifiable execution complete message.

Now I thought that the event would post a message in the application message queue and the WNDPROC will call the proper event handler. But it does not seem to be the case since the event handler which is in the main thread gets called from the worker thread’s context. It sounds strange but that is the way events are working in C# i.e. the execution context of the event handler is same as the execution context in which the event is raised. Internally it might be handled as a direct call instead of PostMessage() that we c++/Win32 people normally expect.

Anyways, one of the problem with these kind of cross-threaded calls is that one cannot update the UI controls in such callbacks. They are deemed unsafe and they are unsafe since the execution contexts are totally different. The .NET compiler/interpreter fortunately helps us to identify such calls. The solution is to check for property InvokeRequired for the control and if it is true, do a self delegate and delegate our call. The next time, InvokeRequired will be false and the call will be made from the main thread’s context since we had delegated it previously. Its a bit twisted but thats how it is supposed to work. I would especially do an InvokeRequired check in events since they are more or less the mechanisms that I use for inter thread communication.

And remember that you need to do this for all the individual controls and it can become quite cumbersome. Fortunately templates are to the rescue. I found a nice snippet on the internet which allows us to make cross-threaded calls without creating delegates explicitly and checking for InvokeRequired on every control function/property. The CrossThreadUtility class is static with a static InvokeControlAction method as shown below.

    public static class CrossThreadUtility
    {
        public static void InvokeControlAction(t cont, Action action) where t : Control
        {
            if (cont.InvokeRequired)
            { 
                cont.Invoke(new Action>(InvokeControlAction), new object[] { cont, action }); 
            }
            else
            { 
                action(cont); 
            }
        }
    }

To use it in your code, just call the InvokeAction in the following manner. I wanted to change the progress bar value to maximum.

CrossThreadUtility.InvokeControlAction(prgBarProgress, tempPrgBar => tempPrgBar.Value = tempPrgBar.Maximum);

The first template parameter is the type of control. In my case it is System.Windows.Forms.ProgressBar, prgBarProgress is my variable associated with that control, tempPrgBar is a temporary progressBar variable created for delegating the cross threaded call. The statement after => is that function that I to call or the property that I want to set. And all these works like a charm.

Use it and forget the headaches about cross-threaded calls and delegates. Have fun computing…