Click here to Skip to main content
15,886,067 members
Articles / Programming Languages / C#

Covering a BackgroundWorker by an Own Class to Lighten the Creation of a Multithread Application

Rate me:
Please Sign up or sign in to vote.
4.79/5 (8 votes)
6 Aug 2015CPOL4 min read 16.7K   473   10   13
The article describes an application that executes several different sorting algorithms on the arrays of integers in the separate threads and graphically visualizes them. The application main thread interacts with the sorting threads using the special C# class that encapsulates a BackgroundWorker.

Introduction

The application has three reasons to be useful. Firstly, it takes a chance to observe the execution of several sorting processes simultaneously. Secondly, it shows how we can cover a BackgroundWorker by an own class in purpose to automate the set up of it. Thirdly, it is an example implementation of the MVC pattern.

Background

Some time ago I used to use a nice training example from the Borland Delphi tutorial - thrddemo - to teach my students how to create a multithread application with the help of the VCL TThread objects. The main advantage of that example was a simple usage of the TThread descendant classes to start the different sorting algorithms in the separate threads. Now I teach C# and need something similar written for the .Net framework. The decision is to apply the BackgroundWorker instances. But a straightforward usage of them leads to a huge amount of a duplicated code. Then I found a helpful tip on codeproject.com in the article "Working with BackgroundWorker & Creating Your Own Loading Class" by Hieuuk and decided to create an own class - BackgroundSorter - to carry out all rough work in it. Now I want to describe the results of my work.

Requirements to the Application

Our goal is to build the multithread application. Its main thread would maintain the GUI and interact with four background threads. Each of them would sort an array of integers by a known sorting algorithm and display every exchange of the array elements on the window of the application. The array would appear on the window as a column of segments. The length of each segment would be proportional to the corresponding element of the array. A user of the application would be able to generate the new arrays before the sorting starts, to start the sorting threads and to terminate any of them ahead of time.

We will use an instance of BackgroundWorker to control a sorting thread. Let it be named bw. Let's recall what we have to do in order to set up it before using. Firstly, we have to define a sorting method and assign it to bw.DoWork event. Then we have to set the properties bw.WorkerSupportsCancellation and bw.WorkerReportsProgress to true and assign a handler method to bw.ProgressChanged event. This event will inform us about the array elements exchanges. And finally, we need to set up a handler to bw.RunWorkerCompleted event.

Naturally, the sorting method must be arranged in a special way so that it can interact with the bw.  It must check the bw.CancellationPending property to break the execution on demand and it should also call bw.ReportProgress() every time an exchange of values is done.

Design of BackgroundSorter

Our new class will act as a mediator between a BackgroundWorker and the outer code. Its tasks are the following:

  1. To join a BackgroundWorker with the array of integers and the sorting method.
  2. To provide the handlers for the events of the BackgroundWorker.
  3. To give a suitable interface to control a sorting thread.
  4. To inform the outer code about the important events in the sorting thread.

So, data members of the BackgroundSorter can look like follows

C#
public class BackgroundSorter
{
    private BackgroundWorker worker;
    private int[] arrayToSort;
    private SortMethod sortMethod;
    // Events affecting the view:
    // - exchange of two array elements
    public event SortingExchangeEventHandler SortingExchange;
    // - completion of the sorting process
    public event SortingCompleteEventHandler SortingComplete;
    // ...

We will use obviously named methods to control the sorting thread (instead of generally named methods of BackgroundWorker).

C#
    // access to the backgroundWorker interface
    public void Execute()
    {
        worker.RunWorkerAsync(arrayToSort);
    }
    public void Stop()
    {
        worker.CancelAsync();
    }

The constructor will set up the worker completely

C#
public BackgroundSorter(int[] array, SortMethod theMethod)
{
    worker = new BackgroundWorker();
    worker.WorkerReportsProgress = true;
    worker.WorkerSupportsCancellation = true;
// Set-up required methods to interact with the backgroundWorker:
// - main long term work
    worker.DoWork += worker_DoWork;
// - action after main work completion
    worker.RunWorkerCompleted += worker_RunWorkerCompleted;
// - displaying of main work progress
    worker.ProgressChanged += worker_ProgressChanged;

    this.arrayToSort = array;
    this.sortMethod = theMethod;
}

Where worker_DoWork, worker_RunWorkerCompleted and worker_ProgressChanged are the methods of the BackgroundSorter. First of them will call the sorting method, second one will check if the worker finished without errors and will inform the application about the sorting completion, third one will translate a "progress changed" message to terms of integers exchange.

C#
// The backgroundWorker events handlers:
// - long term execution - the array sorting
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
    if (sortMethod != null && arrayToSort != null)
    {
        sortMethod((int[])e.Argument, sender as BackgroundWorker, e);
    }
    else throw new NullReferenceException("Trying to use null array or null sorting method");
}
// - handler of completion of the sorting process
private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    if (e.Error != null) MessageBox.Show(e.Error.Message);
    OnSortingComplete(e.Cancelled);
}
// - handler of sorting progress reports indexes of exchanged elements
private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    // the elements indexes are packed in the property ProgressPercentage
    int i = e.ProgressPercentage / 1000;
    int j = e.ProgressPercentage % 1000;
    OnSortingExchange(i, j);
}

Note that the argument of ProgressChanged event can report a single integer but we need at least two ones: indexes of the array elements that have to be exchanged. A simple way to overcome this contradiction is to pack the indexes into a number as follows number=firstIndex​*1000+secondIndex​. It will work with any array not bigger then a thousand of elements.

The complete version of BackgroundSorter you can find in the download files. 

The Application Architecture

Let's briefly describe the entire application. It is built according to the MVC pattern.

The class SortModel acts as the model. It contains four identical arrays and provides the methods for their initialization. The class VisualForm describes the main window of the application and uses four instances of the user control ArraySortingView to display the sorting process. A consideration of the class ArraySortingView is out of this article.

The class SortController encapsulates four instances of BackgroundSorter and uses the static methods of class SortMethodsProvider. Each such method is designed to sort an array and to interact with a background worker simultaneously. Let's take a look at one of them. The interaction part is market with bold.

C#
// Bubble sort algorithm (simple exchange method)
public static void BubbleSortInBackground(int[] arrayToSort, BackgroundWorker worker, DoWorkEventArgs e)
{
    for (int i = arrayToSort.Length - 1; i > 0; --i)
        for (int j = 0; j < i; ++j)
        {
            // Cancel request checking
            if (worker.CancellationPending)
            {
                e.Cancel = true;
                return;
            }
            // Looking for pairs of neighboring elements situated in wrong order
            if (arrayToSort[j] > arrayToSort[j + 1])
            {
                // Exchange vizualization in the main thread
                worker.ReportProgress(j * 1000 + (j + 1));
                System.Threading.Thread.Sleep(delay);
                // The exchange: to correct a "wrong pair" of elements
                int t = arrayToSort[j];
                arrayToSort[j] = arrayToSort[j + 1];
                arrayToSort[j + 1] = t;
            }
        }
}

The application class diagram is shown below. All code of the application is in the download files.

Image 1

Class diagram of the application "Sorting in threads"

Let's look at a screenshot of the running application. Two of four sorting threads are finished and two others are still working.

Image 2

Running application "Sorting in threads"

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Instructor / Trainer Ivan Franko National University of Lviv
Ukraine Ukraine
Head of Programming department in Ivan Franko National University of Lviv, UKRAINE

Comments and Discussions

 
GeneralMy vote of 5 Pin
D V L12-Sep-15 1:35
professionalD V L12-Sep-15 1:35 
GeneralRe: My vote of 5 Pin
Сергій Ярошко12-Sep-15 7:46
professionalСергій Ярошко12-Sep-15 7:46 
GeneralRe: continuation Pin
Сергій Ярошко3-Aug-16 5:57
professionalСергій Ярошко3-Aug-16 5:57 
Generalthanks Pin
Hooman_Kh8-Aug-15 13:17
Hooman_Kh8-Aug-15 13:17 
GeneralRe: thanks Pin
Сергій Ярошко8-Aug-15 20:33
professionalСергій Ярошко8-Aug-15 20:33 
GeneralRe: thanks Pin
Hooman_Kh10-Aug-15 11:07
Hooman_Kh10-Aug-15 11:07 
GeneralRe: thanks Pin
Сергій Ярошко10-Aug-15 21:28
professionalСергій Ярошко10-Aug-15 21:28 
GeneralRe: continuation Pin
Сергій Ярошко3-Aug-16 5:53
professionalСергій Ярошко3-Aug-16 5:53 
QuestionTasks? Pin
ArchAngel1237-Aug-15 9:03
ArchAngel1237-Aug-15 9:03 
AnswerRe: Tasks? Pin
Сергій Ярошко7-Aug-15 20:32
professionalСергій Ярошко7-Aug-15 20:32 
GeneralNice visualisation of sorting in action Pin
John Brett7-Aug-15 4:51
John Brett7-Aug-15 4:51 
GeneralRe: Nice visualisation of sorting in action Pin
Сергій Ярошко7-Aug-15 21:03
professionalСергій Ярошко7-Aug-15 21:03 
GeneralRe: continuation Pin
Сергій Ярошко3-Aug-16 5:58
professionalСергій Ярошко3-Aug-16 5:58 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.