2010-10-04 47 views
5

见下面的程序。 我用功能abc开始一个新的线程x,然后我做一些更长的任务。 为什么x只在end sub之后开始?它不应该马上开始睡觉吗?为什么我的线程不能立即启动?

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 



编辑:
解决的办法是这样的:

(A)将两个连接尝试和超时倒计时到单独的线程。
(B)更新这样的UI:

If Me.InvokeRequired Then 
     Me.Invoke(pUpdateStatusMessage, "Successfully connected.") 
    Else 
     UpdateStatusMessage("Successfully connected.") 
    End If 

有了这个全局声明,所以没有参数传递是必要的:

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 
+0

你如何验证线程只在方法结束后才启动?你在看标签吗?还是你在等待一个断点? – 2010-10-04 16:05:35

+0

实际上,当它没有显示时,我设置了一个断点。 – 2010-10-05 06:52:00

回答

10

abc函数确实会在Button1_Click方法结束之前开始。是什么造成的混乱是2件事

第一个是你直接更新从后台线程的UI具有以下行

Me.lblStatus.Text = "Testing DB connection (timeout in: " + i.ToString() + "s)" 

这个代码不正确,可以在以后导致问题。您必须使用Invoke调用才能真正更改UI。正如你在第二行中所做的那样,这会让我们接触到下一个问题。

Invoke呼叫是同步的。它基本上将消息推送到Windows消息队列中并等待它在返回之前进行处理。主线程中添加的Thread.Sleep调用会阻止消息队列实际运行。这有效地阻止了后台线程,直到Sleep调用完成,从而显示后台线程未运行。

2

你从非更新UI UI线程。这是不允许的,并可能导致奇怪的行为。我不知道这是什么原因导致你的延迟行为,但你需要首先解决。

0

要添加到别人的话,你可以创建一个委托来定义你的控件更新需求的签名(在这种情况下,我假设文本框和字符串,但可以定义,但你需要),和然后创建一个跟随该委托签名的方法,如果需要,它可以异步递归调用它自己。

事情是这样的:

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; 
} 

应该工作,如果它是从“正确的”线程调用(因为InvokeRequired将是错误的,如果这是由拥有控制线程调用)通过简单地更新文本,或从“不正确的”线程(因为InvokeRequired在从不同的线程调用时将为true),通过排队由UI线程执行的调用。

0

也许与您的问题无关,但为了从单独的线程更新UI,我建议您使用BackgroundWorker。在DoWork中放置abc()函数,并使用ProgessChanged更新UI。

相关问题