Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

A Simple Way To Use Asynchronous Call in Your Multithreaded Application

0.00/5 (No votes)
13 Apr 2017 1  
A simple way to use asynchronous calls

Introduction

Running asynchronous tasks can be a nightmare, especially for beginners. In the attached code, you will find a simple AsyncWorker class that can make your life easier, even if you don't know all the background. I would really like to see your contribution to the provided code, especially to the ReportProgress function.

Background

Why did I write this helper class? Simply because I didn't like the .NET BackgroundWorker class and all the issues related with the IsBusy parameter. Sometimes IsBusy does not transit from true to false even if you successfully end the async task. The backgroundWorker forces you to use Application.DoEvents inside a while loop. That's craziness to me. Maybe there is some other way to use it correctly, but I did not find out how. I tried to follow the same design as BackgroundWorker to make replacement as simple as possible.

Using the Code

If you look at the BackgroundWorker documentation, then it should be trivial for you. To initialize the AsyncWorker, simply define:

AsyncCallback m_asyncWorker;		 

And somewhere in your code (constructor), initialize it.

//By setting the maximumCount, we can simulate the simple ThreadPool.
//The maximumCount parameter tells you how many concurrent threads may be
//started simultaneously. Others will wait or be rejected if abortIfBusyParameter
//is set to true.
this.m_asyncWorker = new AsyncWorker(1);

//assign a background task
this.m_asyncWorker.DoWork += new DoWorkEventHandler(m_asyncWorker_DoWork);

Your background task might be anything you like:

void m_asyncWorker_DoWork(object sender, DoWorkEventArgs e) {
    Console.WriteLine("Hello world! I was started asynchronously.");
}  

And finally to call the background worker, simply type:

//because abortIfBusyParameter is set to true, RunWorkerAsync will
//return false (abort the call) if the previous call is still running. 
if (!this.m_asyncWorker.RunWorkerAsync(true)) {
	Console.WriteLine("Worker in use....");
}

By setting RunWorkerAsync parameter abortIfBusy to true, you can skip this event if the previous async call is still running. By setting it to false, it will wait in a queue and will be fired immediately after IsBusy switches from true to false. This mechanism is very helpful in performance sensitive applications. If you have many "low priority" events that start your AsyncCalls and in case that the previous async call is still running (IsBusy), you can decide if another async call should be started or not.

For example: If you are dragging an object on the screen, you do not need to repaint it every time. Just paint it when IsBusy is false. If you would like a smoother effect, simply increase the maximumCount (your thread pool).

At the end, if you need a callback, subscribe yourself to the RunWorkerCompleted event.

//assign to a RunWorkerCompleted. It is your callback event.
this.m_asyncWorker.RunWorkerCompleted += 
	new RunWorkerCompletedEventHandler(m_asyncWorker_RunWorkerCompleted);

Points of Interest

Hope this tool will make your life easier now. Please do not ask about locking in JustDoSomething class. It was part of some other test.

History

  • 6 October, 2009 - First release (Igor Alfirevic)

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here