Big Ball of Mud

Archive for the ‘Multithreading’ Category

Thread Marshalling Part 3 – Automatic Marshalling

with one comment

The last posts from this series showed some basic ways of marshalling background operations in the UI. Now that we know how the BackgroundWorker really works, we can take advantage of some .NET infrastructure and build the component, which will automagically (and this is no April 1st joke) marshall cross-thread calls depending on the execution context. This means we can use it in Windows Forms, WPF, WCF and any other environment which support SynchronizationContext model (even our own!).

In last posts we were using some seriously CPU-wasting empty looping. Let’s take this up one level: what is the more advanced way to create loops in C#? Iterators of course! The component I will show takes any IEnumerable you provide (from iterator block) and iterates through it asynchronously. Each yield return will jump back to the calling thread to notify about the progress. The code below is a modification to the previous EmptyLoop class:

    1     public class IteratingOperation<T>
    2     {
    3         private readonly IEnumerable<T> _loop;
    4         private AsyncOperation _operation;
    5         private bool _cancelled;
    6
    7         public IteratingOperation(IEnumerable<T> loop)
    8         {
    9             _loop = loop;
   10         }
   11
   12         public void Begin()
   13         {
   14             _operation = AsyncOperationManager.CreateOperation(null);
   15             new Action(Iterate).BeginInvoke(null, null);
   16
   17         }
   18
   19         public void Cancel()
   20         {
   21             _cancelled = true;
   22         }
   23
   24         private void Iterate()
   25         {
   26             foreach (var result in _loop)
   27             {
   28                 if (_cancelled)
   29                 {
   30                     _operation.PostOperationCompleted(_ => OnCompleted(true), null);
   31                     return;
   32                 }
   33                 var resultToPost = result;
   34                 _operation.Post(_ => OnUpdateProgress(resultToPost), null);
   35             }
   36             _operation.PostOperationCompleted(_ => OnCompleted(true), null);
   37         }
   38
   39         protected virtual void OnUpdateProgress(T progress)
   40         {
   41             if (UpdateProgress != null)
   42                 UpdateProgress(this, new UpdateProgressEventArgs(progress));
   43         }
   44
   45         protected virtual void OnCompleted(bool cancelled)
   46         {
   47             if (Completed != null)
   48                 Completed(this, new CompletedEventArgs(cancelled));
   49         }
   50
   51         public event EventHandler<UpdateProgressEventArgs> UpdateProgress;
   52         public event EventHandler<CompletedEventArgs> Completed;
   53
   54         public class UpdateProgressEventArgs : EventArgs
   55         {
   56             public T Progress { get; private set; }
   57
   58             public UpdateProgressEventArgs(T progress)
   59             {
   60                 Progress = progress;
   61             }
   62         }
   63
   64         public class CompletedEventArgs : EventArgs
   65         {
   66             public bool Cancelled { get; private set; }
   67
   68             public CompletedEventArgs(bool cancelled)
   69             {
   70                 Cancelled = cancelled;
   71             }
   72         }
   73     }

As you can see, the Begin method calls the Iterate method asynchronously and creates an AsyncOperation instance using AsyncOperationManager class. Both internally handle the appropriate SynchronizationContext. The Iterate method runs the provided loop as usual and calls the events, but uses the AsyncOperation instance to call this on the thread that created the operation. This gives us the safe way to publish these events to the UI. We do not use some parameter-passing features of AsyncOperation, hence lots of nulls in the code.

Because we pass lambdas to Post methods, there is one more interesting line here. If we just pass the result in this line like this:

   34                 _operation.Post(_ => OnUpdateProgress(result), null);

the result variable belongs to the outer scope of the lambda we are passing. This creates a closure and if the result variable gets modified in some way before the lambda is called, the modified version will be used. As the lambda will be called on another thread, there is a chance that the iterating loop will manage to modify it. This is a case when we have a state shared accross threads – the risk I am not willing to take. That’s why I get rid of the modified closure the usual way:

   33                 var resultToPost = result;
   34                 _operation.Post(_ => OnUpdateProgress(resultToPost), null);

The last thing I want to show is the usage of this component on the form (the form itself is the modified version from earlier examples):

    1 public partial class FormWithIterator : Form
    2     {
    3         private IteratingOperation<int> _emptyLoopOperation;
    4
    5         public FormWithIterator()
    6         {
    7             InitializeComponent();
    8         }
    9
   10         private void bStart_Click(object sender, EventArgs e)
   11         {
   12             progressBar.Visible = true;
   13
   14             bCancel.Enabled = true;
   15
   16             _emptyLoopOperation = new IteratingOperation<int>(DoEmptyLoop());
   17             _emptyLoopOperation.UpdateProgress += emptyloop_UpdateProgress;
   18             _emptyLoopOperation.Completed += emptyloop_Completed;
   19             _emptyLoopOperation.Begin();
   20         }
   21
   22         public IEnumerable<int> DoEmptyLoop()
   23         {
   24             var step = 10000000;
   25             for (long i = 0; i < 1000000000; i++)
   26             {
   27                 if (i % step == 0) yield return (int)(i / step);
   28             }
   29         }
   30
   31         private void ShowProgress(int percent)
   32         {
   33             progressBar.Value = percent;
   34         }
   35
   36
   37         private void ShowAlgorithmCompleted()
   38         {
   39             progressBar.Value = 0;
   40             progressBar.Visible = false;
   41             bCancel.Enabled = false;
   42         }
   43
   44
   45         private void emptyloop_UpdateProgress(object sender, IteratingOperation<int>.UpdateProgressEventArgs e)
   46         {
   47             ShowProgress(e.Progress);
   48         }
   49
   50
   51         private void emptyloop_Completed(object sender, IteratingOperation<int>.CompletedEventArgs e)
   52         {
   53             ShowAlgorithmCompleted();
   54         }
   55
   56
   57         private void bCancel_Click(object sender, EventArgs e)
   58         {
   59             _emptyLoopOperation.Cancel();
   60         }
   61     }

As you can see the DoEmptyLoop doesn’t need to know anything about threading and thread marshalling, just like in the case of BackgroundWorker.

Written by bigballofmud

2009/04/01 at 10:43 pm

Posted in C#, Multithreading

Thread Marshalling Part 2 – using BackgroundWorker

leave a comment »

The pattern described in the prevoius post is so common, that .NET 2.0 introduced a new tool to make it easier: BackgroundWorker. Let’s rewrite the code of our form to take advantage of this component:

    
    1     public partial class Main : Form
    2     {
    3         private readonly EmptyLoop _emptyLoop = new EmptyLoop(1000000000);
    4         private readonly BackgroundWorker _bgWorker = new BackgroundWorker();
    5
    6         public Main()
    7         {
    8             InitializeComponent();
    9         }
   10
   11         private void bStart_Click(object sender, EventArgs e)
   12         {
   13             progressBar.Visible = true;
   14             bCancel.Enabled = true;
   15
   16             _emptyLoop.UpdateProgress += algorithm_UpdateProgress;
   17
   18             _bgWorker.WorkerReportsProgress = true;
   19             _bgWorker.WorkerSupportsCancellation = true;
   20             _bgWorker.DoWork += (worker, eventArgs) => _emptyLoop.Go();
   21             _bgWorker.ProgressChanged += (worker, eventArgs) =>
   22                 ShowProgress(eventArgs.ProgressPercentage);
   23             _bgWorker.RunWorkerCompleted += (worker, eventArgs) =>
   24                 ShowAlgorithmCompleted();
   25             _bgWorker.RunWorkerAsync();
   26         }
   27
   28         private void ShowProgress(int percent)
   29         {
   30             progressBar.Value = percent;
   31         }
   32
   33         private void ShowAlgorithmCompleted()
   34         {
   35             progressBar.Value = 0;
   36             progressBar.Visible = false;
   37             bCancel.Enabled = false;
   38         }
   39
   40         private void algorithm_UpdateProgress(object sender,
   41             EmptyLoop.UpdateProgressEventArgs e)
   42         {
   43             if (!_bgWorker.CancellationPending)
   44             {
   45                 _bgWorker.ReportProgress(e.Percent);
   46             }
   47             else
   48             {
   49                 _emptyLoop.Cancel();
   50             }
   51         }
   52
   53         private void bCancel_Click(object sender, EventArgs e)
   54         {
   55             _bgWorker.CancelAsync();
   56         }
   57     }

Looks familiar but there is number of significant differences from prevoius implementation:

  1. The functionality provided by BackgroundWorker class is quite similar to the design of EmptyLoop class. This is not by accident, operations like: reporting progress, cancelling and completing are in fact common to asynchronous operations. We still need to send a message about the progress report from our EmptyLoop and as we would like to keep its implementation clean from any unnecessary dependencies, events are the best way.
  2. Canceling operation is quite different. Cancel button calls BackgroundWorker CancelAsync method, which sets CancellationPending flag to true. Normally DoWork event handler should check this flag and cancel working. In our case we do not have a way to pass the canceling message from DoWork handler, instead we check the cancelling flag in report progress method. This will stop the algorithm a little bit later, but still works.
  3. Finally: thread marshalling method calls: Invoke or BeginInvoke are gone! This is because BackgroundWorker marshals event calls automatically.

The last information is quite interesting, especially if you take into account that the BackgroundWorker lives in System.ComponentModel namespace and is supposed to be a generic asynchronous component – it can be used in WinForms, WPF and any environment you like. Somehow it knows how to do things like thread marshalling.

If we take a look into its RunWorkerAsync method, we can see that it takes advantage of the AsyncOperationManager static class. This static class has one property SynchronizationContext and one method CreateOperation. This members allow the hosting environment (like Windows Forms) set its SynchronizationContext – the object which describes the behaviour required for asynchronous operations. What is interesting, as this an extensible model, we can try to use this mechanism for our purposes.

Written by bigballofmud

2009/03/28 at 9:46 pm

Posted in C#, Multithreading

Thread Marshalling Part 1 – creating a thread in Windows Forms

with 2 comments

Note: Even if you know basics for spawning the new thread in the UI, I recommend performing the following exercise if you never did.

Note: The solutions from this post is not the way how it is done in the 21st century. Stay focused for next parts.

Common situation in Windows Forms development: suppose we want to execute a long-running task, which takes a lot of CPU. The most CPU intensive task I know is running an empty loop:

    for (long i = 0; i < 1000000000; i++)
    {
        // DON'T DO THIS AT HOME
    }

Creating empty loops is a wasteful for both CPU and developer, so lets create something really fancy, seasoned OO professional style:

    
    1     public class EmptyLoop
    2     {
    3         private readonly long _count;
    4         private readonly long _step;
    5         private bool _cancelled;
    6
    7         public EmptyLoop(long countTo)
    8         {
    9             _count = countTo;
   10             _step = countTo / 100;
   11         }
   12
   13         public void Go()
   14         {
   15             _cancelled = false;
   16             for (long i = 0; i < _count; i++)
   17             {
   18                 if (_cancelled) break;
   19                 if (i % _step == 0) OnUpdateProgress((int)(i / _step));
   20             }
   21
   22             OnCompleted(_cancelled);
   23         }
   24
   25         public void Cancel()
   26         {
   27             _cancelled = true;
   28         }
   29
   30         protected virtual void OnUpdateProgress(int percent)
   31         {
   32             if (UpdateProgress != null)
   33                 UpdateProgress(this, new UpdateProgressEventArgs(percent));
   34         }
   35
   36         protected virtual void OnCompleted(bool cancelled)
   37         {
   38             if (Completed != null)
   39                 Completed(this, new CompletedEventArgs(cancelled));
   40         }
   41
   42         public event EventHandler<UpdateProgressEventArgs> UpdateProgress;
   43         public event EventHandler<CompletedEventArgs> Completed;
   44
   45         public class UpdateProgressEventArgs : EventArgs
   46         {
   47             public int Percent { get; private set; }
   48
   49             public UpdateProgressEventArgs(int percent)
   50             {
   51                 Percent = percent;
   52             }
   53         }
   54
   55         public class CompletedEventArgs : EventArgs
   56         {
   57             public bool Cancelled { get; private set; }
   58
   59             public CompletedEventArgs(bool cancelled)
   60             {
   61                 Cancelled = cancelled;
   62             }
   63         }
   64     }

Maybe not so empty now, but you’ve got the point. We have an algorithm, what we need is a form for running it:

multithreading1_form

The code for the form:

    1     public partial class Main : Form
    2     {
    3         private readonly EmptyLoop _emptyLoop = new EmptyLoop(1000000000);
    4
    5         public Main()
    6         {
    7             InitializeComponent();
    8         }
    9
   10         private void bStart_Click(object sender, EventArgs e)
   11         {
   12             progressBar.Visible = true;
   13             bCancel.Enabled = true;
   14
   15             _emptyLoop.UpdateProgress += emptyloop_UpdateProgress;
   16             _emptyLoop.Completed += emptyloop_Completed;
   17
   18             _emptyLoop.Go();
   19         }
   20
   21         private void ShowProgress(int percent)
   22         {
   23             progressBar.Value = percent;
   24         }
   25
   26         private void ShowAlgorithmCompleted()
   27         {
   28             _emptyLoop.UpdateProgress -= emptyloop_UpdateProgress;
   29             _emptyLoop.Completed -= emptyloop_Completed;
   30             progressBar.Value = 0;
   31             progressBar.Visible = false;
   32             bCancel.Enabled = false;
   33         }
   34
   35         private void emptyloop_UpdateProgress(object sender, EmptyLoop.UpdateProgressEventArgs e)
   36         {
   37             ShowProgress(e.Percent);
   38         }
   39
   40         private void emptyloop_Completed(object sender, EmptyLoop.CompletedEventArgs e)
   41         {
   42             ShowAlgorithmCompleted();
   43         }
   44
   45         private void bCancel_Click(object sender, EventArgs e)
   46         {
   47             _emptyLoop.Cancel();
   48         }
   49     }

When we run this simple program, something weird happens (your results may vary): the program seems to do its job by running the loop, but the progress bar is not updated smoothly and when you try to click the Cancel button, the application hangs.

When we realize that each windows form is something of a loop itself, the problem becomes clear – we do not allow the form to update itself by freezing the message loop. Maybe allowing the form to update from time to time will solve the issue:

        private void ShowProgress(int percent)
        {
            progressBar.Value = percent;
            Application.DoEvents();
        }

Better, but no banana. Now Cancel button sometimes work, but the UI still does not react properly and usually the operation completes before the progress bar is filled (wait, haven’t I seen this before?). Clearly the UI is still not refreshed properly. If only we could have a mechanism which would allow to switch from the running algorithm to the UI.

Wait, isn’t it what threads suppose to do? Well they should: it is an abstraction which allows to run things in parallel or just give us the impression of doing it at the level of the system. Let’s remove the DoEvents call and try to run the loop on another thread:

        private void bStart_Click(object sender, EventArgs e)
        {
            progressBar.Visible = true;
            bCancel.Enabled = true;
            _emptyLoop.UpdateProgress += emptyloop_UpdateProgress;
            _emptyLoop.Completed += emptyloop_Completed;
            var loopThread = new Thread(_emptyLoop.Go);
            loopThread.Start();
        }

Oops! As soon as we click the Start button we get InvalidOperationException in ShowProgress method:

        Cross-thread operation not valid: Control 'progressBar' accessed from a thread other than the thread it was created on.

Let me explain what is happening here. When we start the program, the main thread is created for us and this is the thread on which the form and all its controls are run. When we click the Start button, we spawn a new thread in which our empty loop is running. The EmptyLoop class has two events: UpdateProgress and Completed, to which the Form subscribes, so when we run the EmptyLoop method, it occasionally calls two event handlers emptyLoop_UpdateProgress and emptyLoop_Completed. As the EmptyLoop.Go method is called on another thread, so are event handlers. But what event handlers want to achieve is accessing the controls of the form to provide feedback to the user. WinForms controls to be handled properly need to be run only in one thread – the GUI thread. What we need is to jump for a moment to the UI thread for a moment to update the controls. This is called thread marshalling.

Each control has two methods for this: Invoke and BeginInvoke.

        private void algorithm_UpdateProgress(object sender, EmptyLoop.UpdateProgressEventArgs e)
        {
            Invoke(new Action<int>(ShowProgress), e.Percent);
        }
        private void algorithm_Completed(object sender, EmptyLoop.CompletedEventArgs e)
        {
            Invoke(new Action(ShowAlgorithmCompleted));
        }

It does exactly what we need: calls the method on the UI thread. Here we use the methods of the form, but any control will do.

If you need to check from which thread the method is accessed, use InvokeRequired property:

        if (!InvokeRequired)
        {
            ShowProgress(e.Percent);
        }
        else
        {
            Invoke(new Action<int>(ShowProgress), e.Percent);
        }

The difference between Invoke and BeginInvoke is that the computing thread will stop on Invoke until the ShowProgress completes, while BeginInvoke is asynchronous – the computing thread will will just fire and forget ShowProgress and continue its worthless loop spinning.

Written by bigballofmud

2009/03/21 at 8:51 pm

Posted in C#, Multithreading