Article Options
Premium Sponsor
Premium Sponsor

 »  Home  »  .NET Framework  »  Multithreading in VB.NET  »  COM+ Synchronization
Multithreading in VB.NET
by John Spano | Published  07/16/2005 | .NET Framework | Rating:
COM+ Synchronization

COM+ Synchronization

    The dot net framework provides many enterprise services that can be used to build enterprise applications, one of which is the COM+ method of synchronization.  COM+ offers developers many helpful techniques such as transaction handling between objects, loosely coupled events, object pooling and synchronization, which we will discuss here, to name a few.  This synchronization method allows the usage of a concept called a context to provide ways to lock code for synchronization.  This method can be implemented on any class that is derived from ContextBoundObject, or from any class that derives from ContextBoundObject

    When deriving a class from ContextBoundObject, the attribute <SYNCHRONIZATION()>can be used.  This tells the runtime to provide synchronization for the entire class by making each class instance only accessible by one thread at a time.  This case study will give a brief overview of this topic, as it is out of the scope of the article.  Entire books have been written on the subject of COM+.  For further reading on COM+ get a copy of Professional Visual Basic Interoperability – COM and VB6 to .NET, ISBN 1-861005-65-2.

    When you use the attribute, COM+ will create a proxy for you that will run all instances of your object in its context.  COM+ will marshal all calls across this proxy where a performance penalty occurs.  The service guarantees that only one thread is available to run each object at a time. 

    Earlier the timed methods of the WaitHandle classes were discussed.  Recall that the second parameter of the method was a boolean method that determined whether to release the synchronized context along with the object lock.  If your classes use COM+ synchronization True should be passed for this parameter or deadlocks are risked.  True tells COM+ to exit its synchronized context before the runtime allows the thread to wait.  This allows other threads to then get access to the context avoiding deadlocks.  If you don’t exit the context, the .  Net runtime will allow other threads access to the locked object since an exit method has been called.  When the next thread acquires a lock on the locking object it will then try to enter the context, which is still locked resulting in a deadlock. 

    While COM+ synchronization provides another easy way to provide synchronization, be careful when using it.  Many calls to a COM+ synchronized object will degrade your application greatly because of all the marshaling across the proxy.  Be sure to test responsiveness when using it. 

Apartments and Window’s Form Synchronization

    Now that we have examined all the methods that Visual Basic offers for synchronization, we will take a look at Window’s Form projects and what apartment threading is.  The most common types of threading on the Windows platform are single threaded apartments (STA) or multithreaded apartments (MTA).  Window’s forms must be hosted in an STA apartment because some Window’s Form controls are based on standard Windows COM controls that require an STA environment.  Background threads can still be utilized to update forms, but synchronization must be done differently.  As we examine the two apartment styles, we will look at how to do correct synchronization with Window’s Forms. 

    By default all Windows’ Form projects in Visual Basic are STA.  Visual Basic applies the <STATHREAD()>attribute to the main entry point in the application for you behind the scenes.  While you could override this attribute and change it to an MTA apartment, you should not or problems will occur with the COM controls as discussed above. 

    So what is an STA apartment?The apartment concept comes from the early COM days.  Basically, STA means that only one thread can access an object, the thread that created it.  Any future access to the object must also be done on the original thread.  This is the one key reason why you should never update a control on a Window’s Form from another thread.  Most COM objects require STA. 

    MTA, sometimes called free threading, is much harder to program than STA.  This is another reason why we encounter STA COM components most of the time.  MTA means that more than one thread can access an object at any given point in time safely.  When programming for MTA, you must be sure to include good synchronization and design as discussed in the case study.  Any number of threads could be accessing objects in your library at any time. 

    The type of threading model that the current thread is using can be determined simply with the following code. 

Dim sThreadType As String

sThreadType = Thread.CurrentThread.ApartmentState.ToString()

MessageBox.Show(sThreadType)

sThreadType will equal “STA” or “MTA” after the call.  There is also an ApartmentState object that can be set to Thread.CurrentThread.AppartmentState().

Dim Apt as ApartmentState

Apt = Thread.CurrentThread.ApartmentState()

MessageBox.Show(apt.ToString())

    Window’s Form classes provide built in methods to update GUI elements from other threads.  These methods should be used exclusively.  The methods are called Invoke, BeginInvoke, EndInvoke and CreateGraphics.  All of the methods can be called from any thread.  When called, the methods provide a way to work with the control from the main Window’s Form thread.  Let’s see how we can use the methods. 

    The Invoke method takes a delegate for a parameter.  A delegate is basically a variable that points to a method.  The variable in this case tells the Invoke method what function to run.  This delegate is run under the control’s owner thread and not the calling thread, preserving the STA style.  Let’s take a look at a simple example that adds entries to a textbox control using a separate thread.  A button and a multi-line textbox are added to a Window’s Form. 

Private Sub btnStart_Click(ByVal sender As System.Object, ByVal

e As System.EventArgs) Handles btnStart.Click

Dim Thread1 As Thread

Thread1 = New Thread(AddressOf Thread1Work)

Thread1.Start()

End Sub

Private Delegate Sub DelAddItem()

Private Sub Thread1Work()

Dim del As DelAddItem

del = New DelAddItem(AddressOf DelegateWork)

txtList.Invoke(del)

Console.WriteLine("Thread 1 Done")

End Sub

Private Sub DelegateWork()

Dim i As Integer

For i = 0 To 100

txtList.Text = txtList.Text + "A New Line: " &

i.ToString() + vbCrLf

Next 'i

Console.WriteLine("Delegate Done")

End Sub

    To call Invoke, a delegate sub is created.  This sub simply adds a new line to the textbox with the words “A New Line”.  When our new thread is started a new instance of the delegate is created.  The new delegate is then passed to txtList.  Invoke updating the text. 

    The Invoke method runs any code in the delegate synchronously on the thread.  The output from the run will show this:

Delegate Done

Thread 1 Done

Thread 1 will not continue running until the delegate is finished. 

    Sometimes asynchronous calls are preferred.  The BeginInvoke and EndInvoke allow updating the GUI using built in asynchronous technology in the framework.  The two methods take the same delegate that Invoke did.  They only call the code asynchronously.  EndInvoke will return the resulting value from an asynchronous BeginInvoke call.  If the BeginInvoke is still running, EndInvoke will block until the BeginInvoke call finishes.  It will not terminate the BeginInvoke call.  An example is below.

Private Sub btnStart_Click(ByVal sender As System.Object,

ByVal e As System.EventArgs) Handles btnStart.Click

Dim Thread1 As Thread

Thread1 = New Thread(AddressOf Thread1Work)

Thread1.Start()

End Sub

Private Delegate Sub DelAddItem()

Private Sub Thread1Work()

Dim del As DelAddItem

Dim Result As IAsyncResult

del = New DelAddItem(AddressOf DelegateWork)

Result = txtList.BeginInvoke(del)

Console.WriteLine("Thread 1 Done")

Console.WriteLine(Result.IsCompleted.ToString())

txtList.EndInvoke(Result)

Console.WriteLine(Result.IsCompleted.ToString())

End Sub

Private Sub DelegateWork()

Dim i As Integer

For i = 0 To 100

txtList.Text = txtList.Text + "A New Line: " &

i.ToString() + vbCrLf

Next 'i

Console.WriteLine("Delegate Done")

End Sub

Output:

Thread 1 Done

False

Delegate Done

True

    As we see from the output, Thread 1 completed before the delegate finished.  Then the first call to Result.IsCompleted returns false, signifying that the delegate is still running.  Thread 1 is then put to sleep with the EndInvoke call allowing the delegate time to finish.  The next call to Result.IsCompleted returns true.

    The code also shows two methods of getting the status of an asynchronous call.  The first method was the line Result = txtList.BeginInvoke(del).  The Result variable will contain the current results of the asynchronous call.  The other method is with the EndInvoke call, which we said earlier, would block until the asynchronous call is finished.  The last output of true shows that this behavior happened. 

    When using graphics drawing methods with Window’s Forms you must be sure to do all work on the main thread also.  The CreateGraphics method makes sure of this for you.  It can be called from other threads safely like the invoke methods.  The Graphics object returned will run all calls in the correct thread for you.  The Graphics object is considered thread safe so no additional locking objects are necessary. 

Comments    Submit Comment

Comment #1  (Posted by Steven Leadbeater on 08/02/2005)
Rating
Oh My God. this is absolutely brilliant, clear concise and everything works with a minimal amount of tweaking by FAR the best post on threading i have read including anything on MSDN. only wish i could give it a higher rating, nice1
 
Comment #2  (Posted by Ran Oren on 08/14/2005)
Rating
Thanks a lot!!! So clear and simple!
 
Comment #3  (Posted by an unknown user on 08/24/2005)
Rating
Gave me exactly the information I was looking for in a clear way. Thanks
 
Comment #4  (Posted by an unknown user on 08/24/2005)
Rating
None of the books or articles i've read throughout my career has made me understand multi-threading, more than this article.
 
Comment #5  (Posted by an unknown user on 08/24/2005)
Rating
None of the books or articles i've read throughout my career has made me understand multi-threading, more than this article.
 
Comment #6  (Posted by Sulakshana on 08/25/2005)
Rating
Too good,wish I had found this earlier.
 
Comment #7  (Posted by Anonymous on 09/03/2005)
Rating
I agree wholeheartedly with the other comments. This is the only lucid, accessible article I've ever read on the subject. Mr. Spano ought to consider writing a book on the subject--he obviously knows his stuff and how to explain it for us mere mortals.
 
Comment #8  (Posted by an unknown user on 09/07/2005)
Rating
It covered all the salient points.
 
Comment #9  (Posted by an unknown user on 09/21/2005)
Rating
only one word: Excellent!
 
Comment #10  (Posted by Lucas on 10/06/2005)
Rating
Excellent, perfect, great, but the code snippets could be formatted better.
 
Comment #11  (Posted by an unknown user on 12/01/2005)
Rating
good wana more like this
 
Comment #12  (Posted by Sandy Righolme on 12/20/2005)
Rating
Excellent article. Thanks.
 
Comment #13  (Posted by GaZ on 03/30/2006)
Rating
Absolutely spot on article. Very very helpful thanks!
 
Comment #14  (Posted by Marko Hocevar on 04/03/2006)
Rating
I found the article and was very excited to read it...
I also used a piece of code from here in one of my apps but recently discovered that is not working properly. Because threads never share local dynamic variables example in second Public Sub Foo() where piece of code is locked with local variable (=new object()) is not working at all!!

best regards
Mare
 
Comment #15  (Posted by Zoila on 05/16/2006)
Rating
Great Article, so clear and concise. A monkey can understand it... well maybe not a monkey, but I understood it.

Thanks ...
 
Comment #16  (Posted by an unknown user on 06/25/2006)
Rating
Very well written article.
 
Comment #17  (Posted by matroskin on 07/27/2006)
Rating
The example with invoke method, about synchronization of windows forms, does not work, exception in run time
 
Comment #18  (Posted by rimanning on 08/08/2006)
Rating
The other reviewers got it right - this article explains multithreading with great clarity. Good job!
 
Comment #19  (Posted by an unknown user on 10/06/2006)
Rating
This is a Good article - introduces the subject well - flies at 10,000 feet and I enjoyed as a manager but may not be that useful, as a developer except providing a useful background.
 
Comment #20  (Posted by Assaf on 10/16/2006)
Rating
Excellent!
 
Comment #21  (Posted by an unknown user on 10/19/2006)
Rating
Good article
 
Comment #22  (Posted by Mohammad Hefny on 11/12/2006)
Rating
Very great topic...too advanced yet too clear.
I really learned important issues by reading it.
Thank you
 
Comment #23  (Posted by an unknown user on 02/01/2007)
Rating
it's interesting but is's nice to have source code available.
 
Comment #24  (Posted by an unknown user on 06/30/2007)
Rating
Very Cool Article if you have sample code then please send me at sumit.professional@gmail.com or kumar_chams@yahoo.com
 
Comment #25  (Posted by an unknown user on 08/21/2007)
Rating
The examples in your tutorial has some problems. The following Sub is not threadsafe, not commenting on the fact that the method uses a lock to write a local variable. The actual assignment is not threadsafe since each thread calling the method will create a new objLock instance and lock on that, meaning that each thread will in fact be able to get the lock, and do the assignment.

Public Sub Foo()

Dim iData as Integer
Dim objLock as Object = New Object()
SyncLock objLock
iData = 3
End SyncLock
End Sub

Not a very good example. I would think the same problem counts for the monitor examples also.
 
Comment #26  (Posted by an unknown user on 08/21/2007)
Rating
Better than any other article I have seen.
 
Comment #27  (Posted by mm on 10/31/2007)
Rating
This is an excellent article, thanks. To those who complained about the lock being acquired on a local variable - well, duh. Not like it's rocket science to figure that out....
 
Comment #28  (Posted by an unknown user on 12/13/2007)
Rating
I both agree and disagree with Comment #25.

I agree with #25 in that based on some computer generated code in one of my projects the line "Private Shared objLock As New Object" placed in the same class as the Foo() subroutine would resolve the issues that #25 has pointed out.

I disagree with #25's "Not a very good example" statement because it is both an excellent article with excellent examples. If one mistake is all it takes to make something "Not very good" then I submit to all who read this that little to nothing any has every done has ever been "very good".

 
Comment #29  (Posted by an unknown user on 12/14/2007)
Rating
Hey! You can pass values to DelegateWork with the following code:

Private Sub btnStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStart.Click
Dim Thread1 As Thread
Thread1 = New Thread(AddressOf Thread1Work)
Thread1.Start()
End Sub

Private Delegate Sub DelAddItem(ByVal StringHeader As String)
Private Sub Thread1Work()
txtList.Invoke(New DelAddItem(AddressOf DelegateWork), New Object() {"A New Line: "})
Debug.Print("Thread 1 Done")
End Sub
Private Sub DelegateWork(ByVal StringHeader As String)
Dim i As Integer
For i = 0 To 100
txtList.Text = txtList.Text & StringHeader & i.ToString() & vbCrLf
Next 'i
Debug.Print("Delegate Done")
End Sub
 
Comment #30  (Posted by an unknown user on 01/14/2008)
Rating
I have a quuestion, is there a way to implement somthing like a network mutex, where the resources lie on computer 1, and other computers sync to access the resources, please mail me matijasch@yahoo.com, the article is great only this topic is missing, thanks a lot, for helping us
 
Comment #31  (Posted by an unknown user on 01/22/2008)
Rating
brilliant... print and keep, then re-read, re-read, re-read.


 
Comment #32  (Posted by an unknown user on 02/17/2008)
Rating
Great article. Tons of good information. Covered everything that I needed. Thanks, keep writing.
 
Comment #33  (Posted by an unknown user on 02/28/2008)
Rating
Rating says it all
 
Sponsored Links