【问题标题】:Raising Events from a thread safely安全地从线程中引发事件
【发布时间】:2023-03-15 19:47:01
【问题描述】:

我在从非 UI 线程引发的事件方面遇到一些问题,因为我不希望在 Form1 中添加到线程的每个事件处理程序上都处理 If me.invokerequired。

我确定我已经在某处阅读过如何使用委托事件(在 SO 上),但我找不到它。

Public Class Form1

    Private WithEvents _to As New ThreadedOperation

    Private Sub Button_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button.Click
        _to.start()
    End Sub

    Private Sub _to_SomthingHappend(ByVal result As Integer) Handles _to.SomthingHappend
        TextBox.Text = result.ToString //cross thread exception here
    End Sub

End Class

Public Class ThreadedOperation

    Public Event SomthingHappend(ByVal result As Integer)
    Private _thread As Threading.Thread

    Public Sub start()
        If _thread Is Nothing Then
            _thread = New Threading.Thread(AddressOf Work)
        End If
        _thread.Start()
    End Sub

    Private Sub Work()
        For i As Integer = 0 To 10
            RaiseEvent SomthingHappend(i)
            Threading.Thread.Sleep(500)
        Next
    End Sub

End Class

【问题讨论】:

    标签: c# vb.net multithreading


    【解决方案1】:

    您从 Control 派生了您的类。有点不寻常,但如果控件实际上托管在窗体上,则可以使用 Me.Invoke() 来编组调用。例如:

      Private Delegate Sub SomethingHappenedDelegate(ByVal result As Integer)
    
      Private Sub Work()
        For i As Integer = 0 To 10
          Me.Invoke(New SomethingHappenedDelegate(AddressOf SomethingHappenedThreadSafe), i)
          Threading.Thread.Sleep(500)
        Next
      End Sub
    
      Private Sub SomethingHappenedThreadSafe(ByVal result As Integer)
        RaiseEvent SomthingHappend(result)
      End Sub
    

    如果此类对象实际上并未托管在表单上,​​则需要传递对表单的引用,以便它可以调用 Invoke():

      Private mHost As Form
    
      Public Sub New(ByVal host As Form)
        mHost = host
      End Sub
    

    并使用 mHost.Invoke()。或 BeginInvoke()。

    本书的最后一个技巧是使用你的主启动窗体作为同步对象。这并不完全安全,但在 99% 的情况下都有效:

      Dim main As Form = Application.OpenForms(0)
      main.Invoke(New SomethingHappenedDelegate(AddressOf SomethingHappenedThreadSafe), i)
    

    请注意,WF 中存在一个错误,该错误会阻止 OpenForms() 在动态重新创建打开的表单时准确跟踪它们。

    【讨论】:

    • 我接受了第二个建议,传递主机控件(我传递的是控件对象而不是表单)。谢谢
    【解决方案2】:

    如果您想简化这一切,可以使用一个名为 BackgroundWorker 的类来为您处理 GUI 线程封送处理。

    【讨论】:

    • 是的,我知道/使用后台工作器很多,但是这个组件需要对其线程有更大的控制
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多