【问题标题】:Cleanly stopping a thread in VB.net to avoid double error handling干净地停止 VB.net 中的线程以避免双重错误处理
【发布时间】:2021-05-05 14:20:51
【问题描述】:

我遇到了干净地停止线程的问题。我试图将其简化为下面代码的更基本版本,我想知道我的方法是否完全错误。

我的 Form1 带有一堆 UI 元素,需要在 BackgroundCode 运行时进行更新(我在这里运行它,所以它是一个单独的线程,它不会阻止 UI)然后我通过调用 sub 来更新 UI

(Me.Invoke(Sub()
              something.property=something 
           End Sub))

我也在尝试处理一些由外部文件传递给应用程序的错误。我使用了一个计时器来检查文件,如果它存在,我会抓取内容并将其传递给我的 ErrorHandler。这会将错误写入日志文件,将其显示在屏幕上,然后中止后台工作程序,以便程序不会继续运行。我遇到的问题是,通过执行 BackgroundThread.Abort() 操作本身会触发 ErrorHandler。有没有办法让 BackgroundThread 干净地停止?如果该代码中出现其他问题,我希望 BackgroundThread 触发 ErrorHandler。

我想知道如何使用像“ErrorIsRunning”这样的全局布尔值来限制 ErrorHandler 子程序,以便它只能运行一次,但这开始感觉越来越糟糕,我想知道我是否已经走了在这里完全偏离轨道,如果有更好的方法来处理整个事情。

Public Class Form1
    
    Dim BackgroundThread As New Thread(AddressOf BackgroundCode)

    Public Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        
        ‘Hide Error Page
        ErrorPage.Visible = False
        ErrorLabel.Visible = False
        ‘Start Background Code
        BackgroundThread.Start()        
        
    End Sub

    Private Sub BackgroundCode()

        Try
        
            ‘<Background code which runs over a number of minutes>
        
        Catch.ex as Exception
            ErrorHandler(“Error with BackgroundCode: “ + ex.Message)
        End Try
        
    End Sub
    
    Private Sub Timer_Tick(sender As Object, e As EventArgs) Handles Timer.Tick
        
                Dim ErrorFile As String =  “C:\MyErrorFile.Err”
                Dim ErrorContents As String
        
             If File.Exists(ErrorFile) Then

                    Timer.Enabled = False
                    ErrorContents = File.ReadAllText(ErrorFile).Trim()
                    ErrorHandler(ErrorContents)

                End If

        End Sub
    
    Public Sub ErrorHandler(ErrorText As String)


                WriteLog(“ERROR” + ErrorText)
            Me.Invoke(Sub()
                            Me.ErrorPage.Visible = True          
                            Me.ErrorLabel.Text = ErrorText                         
                        End Sub)
            BackgroundThread.Abort()
        End Sub
End Class

【问题讨论】:

  • 这是XY problem吗?
  • 不应使用Thread.Abort。它将“杀死”线程,因此您不知道该线程处于什么状态(因此出现异常)让后台线程不时检查一个布尔值并根据该布尔值结束其循环。现在调用 Thread.Abort 的线程应该设置布尔值。
  • System.Threading.CancellationToken / System.Threading.CancellationTokenSource 专为此用途而设计。见IsCancellationRequested。另见ThrowIfCancellationRequested
  • 嗨,谢谢你,我最终使用了一个后台工作者,而不是仅仅创建一个线程并将其设置为在后台运行(我不完全确定我理解这里的区别)但它确实允许我利用取消请求。虽然在最后一个操作之后立即结束线程并不是我想要的,但这确实意味着我可以很容易地在代码中放置很多断点。

标签: vb.net multithreading


【解决方案1】:

Never abort threads.

这使用一个任务和一个ManualResetEvent。如果不查看后台任务中的代码,很难知道可能需要多少停止检查

Public Class Form1

    Private BackgroundTask As Task
    Private BackgroundTaskRunning As New Threading.ManualResetEvent(True)

    Public Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

        'Hide Error Page
        ErrorPage.Visible = False
        ErrorLabel.Visible = False
        'Start Background Code
        BackgroundTask = Task.Run(Sub() BackgroundCode())

    End Sub

    Private Sub BackgroundCode()

        Try
            '<Background code which runs over a number of minutes>

            'put stop checks periodically
            ' e.g.
            If Not BackgroundTaskRunning.WaitOne(0) Then Exit Sub 'stop check

        Catch ex As Exception
            ErrorHandler("Error with BackgroundCode: " + ex.Message)
        End Try

    End Sub

    Private Sub Timer_Tick(sender As Object, e As EventArgs) Handles Timer.Tick

        Dim ErrorFile As String = "C:\MyErrorFile.Err"
        Dim ErrorContents As String

        If File.Exists(ErrorFile) Then
            Timer.Enabled = False
            ErrorContents = File.ReadAllText(ErrorFile).Trim()
            ErrorHandler(ErrorContents)
        End If

    End Sub

    Public Sub ErrorHandler(ErrorText As String)
        WriteLog("ERROR" + ErrorText)
        Me.Invoke(Sub()
                      Me.ErrorPage.Visible = True
                      Me.ErrorLabel.Text = ErrorText
                  End Sub)
        BackgroundTaskRunning.Reset() 'stop task <<<<<<<<<<<<<<<<<<<<<<<<<<<
    End Sub
End Class

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-07-14
    • 1970-01-01
    • 2012-04-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多