1

一段时间以来,我一直在使用此代码:

Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
    Dim t2 As New Threading.Thread(AddressOf SetLabelText2)
    t2.IsBackground = True
    t2.Start()
End Sub

Delegate Sub UpdateDelegate()

Private Sub SetLabelText2()
    If InvokeRequired Then
        Invoke(New UpdateDelegate(AddressOf SetLabelText2))
    Else
        For i = 1 To 110
            Label2.Text = Text
            Threading.Thread.Sleep(200)
        Next
    End If
End Sub

这段代码运行良好,除了它不是多线程我的应用程序并将其置于无响应状态。

我的问题很简单,1.如何解决这个问题(我将使用的应用程序将有几个函数调用

If InvokeRequired Then

    Invoke(New UpdateDelegate(AddressOf SetLabelText2))

Else

   FunctionCall1()

   FunctionCall2()

   FunctionCall3()

End If

他们都工作并掌握了我的 UI 线程。

我一直在寻找很长一段时间,任何帮助表示赞赏。

-Edit- 在线程中从表单中读取信息时也遇到问题... :) 感谢您迄今为止的帮助

编辑 - -

好的,我已经改变了我的代码看起来像

Delegate Sub setForm1PrgBarPerformStepdelegate(s As Integer) 
    Private Sub setForm1PrgBarPerformStep(ByVal s As Integer)
        If Form1.ProgressBar1.InvokeRequired Then
            Dim d As New setForm1lblAlltextdelegate(AddressOf setForm1PrgBarPerformStep)
            Form1.Invoke(d, New Object() {s})
        Else
            If s = 1 Then
            Form1.ProgressBar1.PerformStep()
        Else

        End If
    End If
End Sub

这段代码是用 setForm1PrgBarPerformStep(1) ' 或 0 调用的

Wich 由我的线程调用,(它可以工作(线程部分 - 女巫很棒顺便说一句),具有不执行执行步骤的小缺陷 - 或我在 Private Sub setForm1PrgBarPerformStep() 中编码的任何其他 UI 更改

这有充分的理由吗?

4

3 回答 3

3

当您的线程第一次点击 SetLabelText2 时,InvokeRequired 将为真,所以

Invoke(New UpdateDelegate(AddressOf SetLabelText2))

将被调用。

现在,在 Invoke 调用中实际发生的是您的线程将把委托作为任务传递给 UI 线程。因此,对 SetLabelText2 的第二次递归调用将由 UI 线程完成,而您的线程只是等待 UI 线程从 SetLabelText2 返回。因此,您的 UI 会阻塞,因为 UI 线程将处于循环中,设置标签文本并处于睡眠状态,并且没有机会处理消息/事件。

作为一种解决方案,您可以在循环中调用 Application.DoEvents() 而不是 Sleep(200),但这可能会产生副作用,因此不建议这样做。

更好的解决方案是将 Invoke 限制为严格必要的 UI 调用,在您的示例中:

Private Sub SetLabelText2()
    For i = 1 To 110
        'Label2.Text = Text
        Invoke(MyDelegateThatDoesNothingButSettingTheLabelText)
        Threading.Thread.Sleep(200)
    Next
End Sub

现在睡眠将由您的线程完成,并且您的 UI 保持响应。

于 2013-04-02T17:20:02.053 回答
0

您的第一个问题是由于调用,SetLabelText2 中的 Sleep 在 UI 线程上而不是在后台线程上被调用。这将导致 UI 显示为锁定状态。新线程仅用于启动 SetLabel,但工作几乎立即返回给调用线程。相反,您需要调用循环内的后台任务,并为每次标签更新委派回 UI。

其次,您不应该在此示例中创建显式线程。从 .Net 4 开始,您应该改用 Tasks。要像使用 Thread.Sleep 一样模拟长时间运行的操作,请使用 Task.Delay(200),然后 Await 或显式调用 .Wait。请记住在后台线程上安排延迟并委托回 UI 更新。

于 2013-04-02T16:59:57.470 回答
0

好的,感谢本节中的评论和一些研究的帮助,我终于弄明白了。

我有点被运行 UI 线程欺骗了一点,只是为了在循环或短时间内完成繁重的工作而爆发,这里有一些代码 - 希望这对其他人有帮助。

Public t2 As Threading.Thread ' Instantiating the Thread. I do this in my Modules
                              ' You will want to do this for all threads needed.

'You would then go through your program like normal until you hit a heavy process eating point,
'For me it was when i was converting images and sending them / moving them across the network

'So to get what i wanted i used this in the middle of my public Function

    For Each s As String In sFiles
        c += 1 'This was just a simple file counter for the prg bar

CheckAgain:
        If t3 Is Nothing Then
            t3 = New Thread(New ParameterizedThreadStart(AddressOf DoWork))
            t3.Start(s)
            GoTo NextOne
        ElseIf t4 Is Nothing Then
            t4 = New Thread(New ParameterizedThreadStart(AddressOf DoWork))
            t4.Start(s)
            GoTo NextOne
        ElseIf t5 Is Nothing Then
            t5 = New Thread(New ParameterizedThreadStart(AddressOf DoWork))
            t5.Start(s)
            GoTo NextOne
        ElseIf t6 Is Nothing Then
            t6 = New Thread(New ParameterizedThreadStart(AddressOf DoWork))
            t6.Start(s)
            GoTo NextOne
        ElseIf t7 Is Nothing Then
            t7 = New Thread(New ParameterizedThreadStart(AddressOf DoWork))
            t7.Start(s)
            GoTo NextOne
        ElseIf t8 Is Nothing Then
            t8 = New Thread(New ParameterizedThreadStart(AddressOf DoWork))
            t8.Start(s)
            GoTo NextOne
        ElseIf t9 Is Nothing Then
            t9 = New Thread(New ParameterizedThreadStart(AddressOf DoWork))
            t9.Start(s)
            GoTo NextOne
        Else
            GoTo CheckAgain
        End If
NextOne:
    Next

Sub DoWork(ByVal s As Object)

        ChangeCompression("Variables for my Function that did alot of work")
        'System.Threading.Thread.Sleep(10)

    'This is how i disposed of my threads

    If Not (t3 Is Nothing) Then
        t3 = Nothing
    ElseIf Not (t4 Is Nothing) Then
        t4 = Nothing
    ElseIf Not (t5 Is Nothing) Then
        t5 = Nothing
    ElseIf Not (t6 Is Nothing) Then
        t6 = Nothing
    ElseIf Not (t7 Is Nothing) Then
        t7 = Nothing
    ElseIf Not (t8 Is Nothing) Then
        t8 = Nothing
    ElseIf Not (t9 Is Nothing) Then
        t9 = Nothing
    End If

End Sub

仅此而已:)-希望这可以帮助某人,并感谢所有人帮助我完成了我的多线程工作,是的...我知道有更好的方法,但这对我有用:)

于 2013-04-04T13:30:16.267 回答