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 スレッドを取得します。

私はかなり長い間探していましたが、助けていただければ幸いです。

-編集- また、フォームから情報を読み取るためにスレッド内で問題が発生しています... :) これまでの助けに感謝します

編集 - -

OK、コードを次のように変更しました

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 で呼び出されています

ウィッチは私のスレッドによって呼び出されます (それは機能します (スレッド部分 - 魔女は素晴らしいところで)、実行ステップを実行しないという小さな欠陥があります - またはその他の UI の変更はプライベート サブ setForm1PrgBarPerformStep() でコーディングします)

これには正当な理由がありますか?

4

3 に答える 3

3

スレッドが最初に SetLabelText2 にヒットすると、InvokeRequired が true になるため、

Invoke(New UpdateDelegate(AddressOf SetLabelText2))

が呼び出されます。

ここで、Invoke 呼び出し内で実際に起こることは、スレッドがデリゲートをタスクとして UI スレッドに渡すことです。そのため、SetLabelText2 への 2 番目の再帰呼び出しは UI スレッドによって実行され、スレッドはただ座って UI スレッドが SetLabelText2 から戻るのを待ちます。UIスレッドがループに入ってラベルテキストを設定し、スリープ状態になり、メッセージ/イベントを処理する機会がないため、UIがブロックされます。

解決策として、Sleep(200) の代わりに、ループ内で Application.DoEvents() を呼び出すことができますが、これには副作用がある可能性があるため、お勧めしません。

より良い解決策は、あなたの例では、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

わかりました、このセクションで行われたコメントといくつかの調査の助けのおかげで、私は最終的にそれを理解しました.

私は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

そして、それだけでした:)-これが誰かを助けることができることを願っています、そして私がMYを手に入れるのを手伝ってくれてありがとう-ちょっとマルチスレッドを完了させてください...私はより良い方法があることを知っていますが、これは私のために働きます:)

于 2013-04-04T13:30:16.267 に答える
0

最初の問題は、SetLabelText2 の Sleep が Invoke のためにバックグラウンド スレッドではなく UI スレッドで呼び出されていることです。これにより、UI がロックされているように見えます。新しいスレッドは SetLabel を起動するためにのみ使用されますが、作業はほとんどすぐに呼び出し元のスレッドに返されます。代わりに、ループ内でバックグラウンド タスクを呼び出し、ラベルの更新ごとに UI に委任する必要があります。

次に、この例では明示的なスレッドを作成しないでください。.Net 4 以降では、代わりに Tasks を使用する必要があります。Thread.Sleep で行っているように長時間実行される操作をシミュレートするには、Task.Delay(200) を使用してから、それを Await するか、明示的に .Wait を呼び出します。バックグラウンド スレッドで遅延をスケジュールし、UI の更新を委任することを忘れないでください。

于 2013-04-02T16:59:57.470 に答える