C# Tutorials and offshore development in India
    Tutorials   Resources   Forum   Reviews   Communities   Interview   Jobs   Projects   Training   Your Ad Here    
Silverlight Games | Mentor | Code Converter | Articles | Code Factory | Computer Jokes | Members | Peer Appraisal | IT Companies | Bookmarks | Polls | Revenue Sharing | Lobby | Gift Shop |


Prizes & Awards
My Profile



Active Members
TodayLast 7 Days more...






Resources » Articles » .NET Framework »

Multithreading in .NET # UI thread & Worker threads


Posted Date: 21 Jul 2004    Resource Type: Articles    Category: .NET Framework
Author: PalashMember Level: Bronze    
Rating: 1 out of 5Points: 10



Multithreading enables an application to do more than one task at a time. Using multithreading, we can have one thread run the user interface while another thread does intensive calculations or processing in the background. Unfortunately, multithreading has its darker side as well. Any time an application uses more than one thread, we can run into problems where multiple threads try to interact with the same data or resources at the same time. Any time this happens, things tend to get very complex and hard to debug.

Visual Basic 6 code always ran in a single-threaded apartment (STA), so our code would only ever have a single thread to worry about. In .NET there is no such thing as an STA. All .NET code runs within an AppDomain, which allows multithreading. Obviously, any time we do this, our code must be written carefully to avoid conflicts between threads.

There are many reasons to use multithreading in an application, but one of the most common is that we have a long-running task to perform and we want some or all of the user interface to remain responsive to the user. For example, we typically want a Cancel button to remain responsive so users can terminate the long-running task. While requesting a cancel operation is important, we'll also most likely want the UI to display status information from the background process for the user. This may be in the form of text messages, or a percentage complete, or both.

In Visual Basic 6, we tried to do this by using DoEvents and timer controls and a host of other workarounds. Where in .NET things are much simpler because we can use multithreading. But the major complication we'll face when implementing a Cancel button or status display in .NET is that the Windows Forms library is not thread-safe. This simply means that only the thread that created a form can interact with that form and its controls. No other thread can safely interact with the form or its controls. Typically an application will start with a single thread that opens the user interface. This thread is called the UI thread. In many applications this is the only thread we use, so it handles the UI as well as does all our processing. But it is not a good practice at all, because it will make the UI non-responsive. It is better to create a worker thread or more to do background processing, leaving the UI thread to focus on the user interface so it remains responsive to the user even while worker thread is busily at work.

To do this, we'll use the Form object's Invoke method (This is thread-safe). This method accepts a delegate pointer to the method the form should call, along with an array of type Object that contains the parameters for the method (A delegate is a formal pointer to a method, and a delegate for a method must have the same method signature (parameter types, etc.) as the method itself). The Invoke method doesn't directly call the method on the form. Instead, it basically asks the form to turn around and call the method using the form's UI thread. This is done behind the scenes by sending a Windows message to the form. This means the form gets these method calls much the same way it gets a click or keypress event from the operating system itself. The result is that the Invoke method triggers a process by which the form ends up running the method on its UI thread, which is our desired goal. This whole process is synchronous - meaning that the worker thread is blocked while the call is made to the form. While blocking the worker thread for an error or completed message is fine, we probably don't want to block it for every little status display. To avoid blocking on the status display, we use BeginInvoke (This is also thread-safe) instead of Invoke. BeginInvoke causes the invocation of the method on the form to be done asynchronously, so the worker thread can keep on running without waiting for the form's method to complete.

Example: For example, consider a time-consuming problem, like – ‘calculation of the factorial of a big number’, ‘finding all prime numbers within a given range’, ‘reading & parsing of a huge text file’ or ‘calling a Web service’. For simplicity, take the ‘finding all prime numbers within a given range’ problem. Please take a look at the different Buttons’ Click events.

Button 1: No worker Thread. So UI will behave like a hanged one. ‘Cancel’ button will not work here. Here you can call the UI methods directly, because this is executing under the UI thread itself.


Private Sub btnUIonly_Click(ByVal sender As System.Object, ByVal e As _
System.EventArgs) Handles btnUIonly.Click
Dim i As Integer
SetUI()
For i = m_Min To m_Max
UpdateProgreass(i)
If IsPrime(i) Then
UpdateResult(i.ToString())
End If
If m_cancel Then
Exit For
End If
Next i
ResetUI()
End Sub


Button 2: A worker thread is there. But it is calling the UI methods (SetUI(), ResetUI(),UpdateProgreass(),UpdateResult() ) directly which is not thread safe.


Private Sub btnWorkerNonSafe_Click(ByVal sender As System.Object, ByVal e As _
System.EventArgs) Handles btnWorkerNonSafe.Click
Dim thread As New thread(AddressOf FindPrime_NonThreadSafe)
thread.Start()
End Sub

Private Sub FindPrime_NonThreadSafe()
Dim i As Integer
SetUI()
For i = m_Min To m_Max
UpdateProgreass(i)
If IsPrime(i) Then
UpdateResult(i.ToString())
End If
If m_cancel Then
Exit For
End If
Next i
ResetUI()
End Sub


Button 3: Worker thread here too. And this worker thread is calling the UI methods through Invoke/BeginInvoke methods. This is the way it should be.

Private Sub btnWorkerSafe_Click(ByVal sender As System.Object, ByVal e As _
System.EventArgs) Handles btnWorkerSafe.Click
Dim thread As New thread(AddressOf FindPrime_ThreadSafe)
thread.Start()
End Sub

Private Sub FindPrime_ThreadSafe()
Dim i As Integer
Invoke(New SetResetUIEventHandler(AddressOf SetUI))
For i = m_Min To m_Max
Invoke(New UpdateProgreassEventHandler(AddressOf UpdateProgreass), New Object() {i})
If IsPrime(i) Then
Invoke(New UpdateResultEventHandler(AddressOf UpdateResult), New Object() {i.ToString()})
End If
If m_cancel Then
Exit For
End If
Next i
Invoke(New SetResetUIEventHandler(AddressOf ResetUI))
End Sub

Private Delegate Sub UpdateProgreassEventHandler(ByVal value As Integer)
Private Delegate Sub UpdateResultEventHandler(ByVal [string] As String)
Private Delegate Sub SetResetUIEventHandler()


NB. Invoke and BeginInvoke add overhead to the process. So too frequent call of Invoke and/or BeginInvoke will slow down process-execution. So in a loop it is better to call Invoke/BeginInvoke on alternative 10 times (or more, based on your loop-size).



Responses

Author: saradakishore Potluri    27 Oct 2004Member Level: Bronze   Points : 0
This article is verygood and useful


Feedbacks      
Popular Tags   What are tags ?   Search Tags  
Sign In to add tags.
(No tags found.)

Post Feedback


This is a strictly moderated forum. Only approved messages will appear in the site. Please use 'Spell Check' in Google toolbar before you submit.
You must Sign In to post a response.
Next Resource: How to GET the message count of MSMQ in .NET withoutPerformanceCounter?
Previous Resource: Label control with gradient property
Return to Discussion Resource Index
Post New Resource
Category: .NET Framework


Post resources and earn money!
 
More Resources



dotNet Slackers

About Us    Contact Us    Privacy Policy    Terms Of Use