Why is my thread not starting immediately?
see below program. I start a new thread x with function abc, then I do some longer task. Why does x only start after end sub? Shouldn't it start right-away, before sleep ?
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim x As New Threading.Thread(AddressOf abc)
x.SetApartmentState(Threading.ApartmentState.MTA)
x.Start()
System.Threading.Thread.Sleep(5000)
End Sub
Sub abc()
For i As Integer = 0 To 10 Step 1
Me.lblStatus.Text = "Testing DB connection ( timeout in: " + i.ToString() + "s )"
'Me.StatusStrip1.Invoke(
MsgBox(i.ToString)
System.Threading.Thread.Sleep(1000)
Next
End Sub
Edit:
The solution is this:(A) Put both the co开发者_如何学Cnnection attempts and the timeout countdown into separate threads.
(B) Update the UI like this: If Me.InvokeRequired Then
Me.Invoke(pUpdateStatusMessage, "Successfully connected.")
Else
UpdateStatusMessage("Successfully connected.")
End If
With this globally declared, so no argument passing is necessary:
Delegate Sub t_pUpdateStatusText(ByVal strMessage As String)
Public pUpdateStatusMessage As t_pUpdateStatusText = New t_pUpdateStatusText(AddressOf UpdateStatusMessage)
Public Sub UpdateStatusMessage(ByVal strMessage As String)
Me.lblStatus.Text = strMessage
Me.StatusStrip1.Update()
End Sub
The abc
function will indeed start before the Button1_Click
method ends. What's causing the confusion is 2 things
The first is that you are directly updating the UI from a background thread with the following line
Me.lblStatus.Text = "Testing DB connection ( timeout in: " + i.ToString() + "s )"
This code is incorrect and can cause issues later on. You must use the Invoke call in order to actually change the UI. As you do in the second line which brings us to the next problem.
The Invoke
call is synchronous. It runs by essentially pushing a message onto the windows message queue and waiting for it to be processed before returning. The Thread.Sleep
call you added in the main thread prevents the message queue from actually running. This effectively stalls the background thread until the Sleep
call completes giving the appearance that the background thread is not running.
You're updating your UI from a non-UI thread. This is not allowed, and can lead to odd behavior. I don't know if that's what's causing your delay behavior, but you'll need to solve that first.
To add to what others are saying, you can create a delegate to define the signature of your control update requirements (in this case, I'm assuming textbox and string, but that can be defined however you need), and then create a method that follows that delegate signature which recursively invokes itself asynchronously if need be.
Something like this:
private delegate void ControlUpdateTextHandler(TextBox ctrl, string text);
public void UpdateControlText(TextBox ctrl, string text)
{
if (ctrl.InvokeRequired)
{
ctrl.BeginInvoke((ControlUpdateTextHandler)UpdateControlText, ctrl, text);
}
else
ctrl.Text = text;
}
Should work if it's called from the "correct" thread (because InvokeRequired will be false if this is called by the thread that owns the control) by simply updating the text, or from the "incorrect" thread (becasue InvokeRequired will be true if called from a different thread), by queuing up the invocation to be performed by the UI thread.
Maybe not related to your question,but for updating the UI from a separate thread, I suggest you use the BackgroundWorker. place the abc() function in DoWork and use ProgessChanged to update the UI.
精彩评论