Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1480
  • Last Modified:

VB.NET Threading Questions - Worker Thread Hanging the UI!

Hi Experts,

I use threading all through a large application and have encountered a problem that i can't work out!

I am writing a single 'server' application to do a number of jobs for the company, this will involve mainly syncing up the website and doing some database work every few seconds. One of the other applications is checking SMS messages on a connected Nokia phone and handle them (i.e. send them off in an e-mail, write replies etc)

The issue is that every time i check the phone, the application hangs ... the obvious solution was to put the method into a thread that i simply fire off every 20 seconds.

Now that i have moved the method into a thread using the following:

Dim oThread As New Threading.Thread(AddressOf RefreshNokiaInbox)
oThread.Priority = Threading.ThreadPriority.Lowest
oThread.Start()

 Private Sub RefreshNokiaInbox()
        Dim oColl As HTFR.Objects.NokiaSMS.NokiaInternalStructures.NokiaObj_SMSItemCollection = HTFR.Objects.NokiaSMS.NokiaInternalStructures.NokiaObj_SMSItemCollection.GetBlankCollection
        Try
            'Tell the UI Thread that we are refreshing the Inbox
            Dim oDel As New del_SubCallbackNoArgs(AddressOf RefreshNokiaInbox_Callback_Started)
            HTFR.Objects.SharedElements.Objects.MDIForm.Invoke(oDel)

           'returns a collection of business objects containing the sms message details on the phone
            oColl = m_oNokiaPhoneItem.Inbox

        Catch ex As Exception
            HTFR.Objects.SharedElements.Methods.RaiseQuickError(ex)
        Finally
            'Tell the UI thread that we have completed
            Dim oDelComp As New del_RefreshInboxCallback(AddressOf RefreshNokiaInbox_Callback_Comp)
            HTFR.Objects.SharedElements.Objects.MDIForm.Invoke(oDelComp, oColl)
        End Try
    End Sub

Now, the issie is, that when this method is run ... the main UI still hangs!

My understanding is that if i put something in a thread, it doesn't touch the main UI until i make a callback with a delegate, so how can a worker thread lock up the main UI (but not the whole computer?)

The one thing i didn't want to do was write a different application for each job that i need to perform, surely firing off a thread for each 'job' is the same as having them running as different applications or does the OS handle the seperate programs better?
0
Gweep
Asked:
Gweep
  • 6
  • 3
  • 3
2 Solutions
 
ClausewitzCommented:
running it in another thread does not solve this problem. Your UI-Thread is still waiting for the result from the other thread.

Use an asynchronous callback and the UI won't be hanging any more.
http://msdn.microsoft.com/en-us/library/ms228969.aspx
0
 
GweepAuthor Commented:
Eh?

What do you mean when you say that my UI thread is still waiting for the callback?

Are you saying that after calling the Thread.Start that my UI thread will hang and wait for the callback from the worker thread?

Surely while the UI is waiting for the callback from the worker thread it is also free to do any other processing on it because i havn't joined the threads?

Can you explain please?
0
 
ClausewitzCommented:
i thought you were calling the code you listed above from inside of your UI, sorry.
How do you call the Sub RefreshNokiaInbox? Are you sure it is called from the worker thread?
0
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 
Mike TomlinsonMiddle School Assistant TeacherCommented:
I am often perplexed at what people do with threads...   =\

Please study the example below.  Each of the three buttons below shows a different approach.  I believe what you are doing is "equivalent" to what is happening in Button2.
Public Class Form1
 
    Public Delegate Sub DelayDelegate()
 
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim T As New System.Threading.Thread(AddressOf Delay)
        T.Start()
    End Sub
 
    Private Sub Delay()
        ' do some "work"...main UI thread remains free and responsive
        System.Threading.Thread.Sleep(10000)
        MessageBox.Show("Done") ' <-- not really kosher to do from a thread...but we'll ignore this
    End Sub
 
    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        Dim T As New System.Threading.Thread(AddressOf DelayWithInvoke)
        T.Start()
    End Sub
 
    Private Sub DelayWithInvoke()
        ' consider the line of code below:
        Me.Invoke(New DelayDelegate(AddressOf Delay))
 
        ' Translation: Take the Delegate (which points to the Delay method), and run it on
        ' whatever thread owns "Me" (the Form).
 
        ' So even though this method, DelayWithInvoke(), is running in it's own thread,
        ' the Delay() method will be run on the main UI's thread causing it to lock up.
 
        ' What was the point of creating a new thread?!
 
        ' We essentially "negated" the whole point of a new thread by telling
        ' the system to take the "work" and do it on the thread we were trying to free up
        ' in the first place!
    End Sub
 
    Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
        Button3.Enabled = False
        Dim T As New System.Threading.Thread(AddressOf DelayWithInvokeUsedProperly)
        T.Start()
    End Sub
 
    Private Sub DelayWithInvokeUsedProperly()
        ' do some "work" on the THREAD WE CREATED
        System.Threading.Thread.Sleep(10000)
 
        ' Turn button3 back on using Invoke()...
        ' ...this needs to be done back on the main UI thread!
        ReEnableButton3()
    End Sub
 
    Private Sub ReEnableButton3()
        If Me.InvokeRequired Then
            Me.Invoke(New DelayDelegate(AddressOf ReEnableButton3))
        Else
            Button3.Enabled = True
        End If
    End Sub
 
End Class

Open in new window

0
 
GweepAuthor Commented:
Heh .... no, what i am actually doing is closer to button 3.

The RefreshNokiaInbox sub would be run in the worker thread and then i use delegates to call back with progress and a final completed call, passing in the collection of business objects so a grid can be populated.

Give me a second and i'll write what i'm doing in your example....
0
 
GweepAuthor Commented:
Here we go ...
Private Sub Button4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button4.Click
        Dim T As New System.Threading.Thread(AddressOf DelayWithInvokeUsedProperly)
        T.Start()
    End Sub
 
    Private Sub RefreshNokiaInbox()
        Dim oColl As BusinessObjectCollection = NokiaPhoneClass.BlankCollection
        Try
            oColl = NokiaPhoneClass.Inbox
 
            System.Threading.Thread.Sleep(10000)
 
        Catch ex As Exception
            'handle the error
        Finally
            Dim oDel as del_Callback(Addressof CallbackSub)
            Me.invoke(odel, oColl)
        End Try
    End Sub
 
    Private Sub CallbackSub(ByVal Collection As BusinessObjectCollection)
        Grid.Datasource = Collection
    End Sub

Open in new window

0
 
GweepAuthor Commented:
My problem is that while the worker thread is running the 'RefreshNokiaInbox' sub, the main UI will hang and become unresponsive.

I've done this a thousand times before while waiting for database calls etc without a problem but the Nokia Interop that i'm connecting too seems to slow it right down.

I guess my question is that how come my application hangs while i'm running it in a thread, and not the whole computer. This would elad me to believe that if i want to run many jobs on one computer it would be better to run them as seperate applications rather than one 'cleaner' application that does it all with threads

Would i be right?
0
 
GweepAuthor Commented:
Sorry ... edit to the code example

Read the line
Dim T As New System.Threading.Thread(AddressOf DelayWithInvokeUsedProperly)

As
Dim T As New System.Threading.Thread(AddressOf RefreshNokiaInbox)
0
 
ClausewitzCommented:
You have a coupling via Dim oColl As BusinessObjectCollection in your Sub RefreshNokiaInbox.

The business object is declared in your Sub running in the worker thread. When the UI-Thread wants to read and process it, it must wait until the worker thread is responding.
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
I would say the problem lies INSIDE NokiaPhoneClass then:

    oColl = NokiaPhoneClass.Inbox

Is this an external control that is dropped on your form?  Perhaps it was designed badly and is internally using Invoke() on it's parent container.   =\
0
 
GweepAuthor Commented:
Clausewitz:
Could you explain to me what you mean by 'Coupling' please?

Idle_Mind:
The NokiaPhoneClass.Inbox is a wrapper that interfaces with a NokiaPhone via a serial lead. I know that this is where the problem lies, i just wanted to check that there wasn't any other way of calling a thread that would mean the worker thread was completely detached from the UI thread that called it.

Either way, i released a tweaked version and without the IDE, the program does not seem to lock up.

I'll still give you guys the points for effort tho ;)
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
Glad you figured it out...  =)
0

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

  • 6
  • 3
  • 3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now