【问题标题】:Stackoverflow error in BackgroundWorker ProgressChangedBackgroundWorker ProgressChanged 中的 Stackoverflow 错误
【发布时间】:2011-09-28 02:51:30
【问题描述】:

我的程序中有一个搜索功能,它使用后台工作程序来获取结果。 Progress changed 事件用于使用新项目更新列表视图。

Private Sub SearchWorker_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles SearchWorker.ProgressChanged
    Dim itmX As ListViewItem
    Dim tmpCustomer As CustomerItem

    If e.UserState.ToString = "New" Then
        lstResults.Items.Clear()
    Else
        Try
            tmpCustomer = e.UserState
            itmX = lstResults.Items.Add(tmpCustomer.CustomerName) ' <-- Error here
            itmX.Tag = tmpCustomer.CustomerID
            itmX.Name = tmpCustomer.CustomerID
            itmX.SubItems.Add(tmpCustomer.City)
            itmX.SubItems.Add(tmpCustomer.State)
            itmX.SubItems.Add(tmpCustomer.Zip)
        Catch ex As Exception
            MsgBox(ex.Message)
        End Try
    End If

    progBar.Value = e.ProgressPercentage

    Application.DoEvents()
End Sub

我得到了这个错误

An unhandled exception of type 'System.StackOverflowException' occurred in System.Windows.Forms.dll

我试过了,但没有任何区别

Private Sub SearchWorker_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles SearchWorker.ProgressChanged

    If e.UserState.ToString = "New" Then
        lstResults.Items.Clear()
    Else
        Try
            itmX = lstResults.Items.Add("Test")
        Catch ex As Exception
            MsgBox(ex.Message)
        End Try
    End If

    progBar.Value = e.ProgressPercentage

    Application.DoEvents()
End Sub

编辑: 哦,如果我只是单步执行代码,它没有任何问题。

编辑 2:
这是后台工作者 DoWork 事件:

Sub doSearch(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles SearchWorker.DoWork
    canceled = False
    If curSearch = doSearchText Then
        canceled = True
        Exit Sub
    End If
    curSearch = doSearchText

    SearchWorker.ReportProgress(0, "New")
    Dim rSelect As New ADODB.Recordset
    Dim CustomerID As Integer = MakeNumeric(doSearchText)
    Dim sSql As String = "SELECT DISTINCT CustomerID, CustomerName, City, State, Zip FROM qrySearchFieldsQuick WHERE "
    Dim sWhere As String = "CustomerID = " & CustomerID & " OR CustomerName Like '" & doSearchText & "%'"
    If Not doSearchText.Contains(" ") Then
        sWhere &= " OR FirstName Like '" & doSearchText & "%' OR LastName Like '" & doSearchText & "%'"
    Else
        Dim str() As String = doSearchText.Split(" ")
        sWhere &= " OR (FirstName Like '" & str(0) & "%' AND LastName Like '" & str(1) & "%')"
    End If

    Dim i As Integer = 0
    Dim tmpCustomer As CustomerItem

    With rSelect
        .Open(sSql & sWhere & " ORDER BY CustomerName", MyCn, ADODB.CursorTypeEnum.adOpenStatic, ADODB.LockTypeEnum.adLockReadOnly)
        Do While Not .EOF
            If SearchWorker.CancellationPending Then
                canceled = True
                Exit Do
            End If

            Do While IsDBNull(.Fields("CustomerID").Value)
                .MoveNext()
            Loop

            tmpCustomer.CustomerID = "c" & .Fields("CustomerID").Value
            tmpCustomer.CustomerName = NZ(.Fields("CustomerName").Value, "").ToString.Trim
            tmpCustomer.City = Trim(NZ(.Fields("City").Value, ""))
            tmpCustomer.State = Replace(Trim(NZ(.Fields("State").Value, "")), ",", "")
            tmpCustomer.Zip = Trim(NZ(.Fields("Zip").Value, ""))

            SearchWorker.ReportProgress((i / .RecordCount) * 100, tmpCustomer)
            i += 1
            Application.DoEvents()
aMoveNext:

            .MoveNext()
        Loop
        .Close()
    End With
End Sub

【问题讨论】:

  • 后台工作人员是否在与 lstResults 相关的事件中被触发?我们能看到它被启动的方法吗?
  • 你能给我们看看 StackTrace 吗?

标签: vb.net backgroundworker


【解决方案1】:

我认为问题可能出在这一行:

Application.DoEvents()

如果您的BackgroundWorker 排队ProgressChanged 事件的速度足够快,则每次调用Application.DoEvents() 都将通过消息队列,来到ProgressChanged 事件,更新进度,调用Application.DoEvents(),完成消息队列,出现ProgressChanged 事件等。本质上会导致代码中的递归行为。

尝试删除该呼叫,看看问题是否消失。

【讨论】:

    【解决方案2】:
    Application.DoEvents()
    

    那就是麻烦制造者。您添加它是因为您注意到用户界面仍然冻结,即使您使用了 BGW。问题是,当它泵送事件时,您的 BGW 再次调用了 ReportProgress。导致 ProgressChanged 再次运行。导致 DoEvents 再次被调用。这可能会持续几秒钟,直到 ui 线程用完堆栈空间。卡布姆。

    您必须删除 DoEvents() 调用。并解决真正的问题,您的 BGW 过于频繁地调用 ReportProgress 方式。导致 ui 线程被调用 ProgressChanged 的​​调用请求淹没。导致它不再履行其日常职责。包括绘画和响应用户输入。

    每秒调用 ReportProgress 的次数不超过 20 次。这在人眼看来是平滑的。收集计算结果,以便您准备好处理大量工作。如果您的 Worker 产生结果的速度比 ui 线程显示它们的速度快,那么您别无选择,只能强制减慢它的速度。

    【讨论】:

    • 感谢您的解释。这是我的第一次多线程冒险,所以这会有所帮助。在将它们传递给进度报告器之前​​,我必须先研究要收集多少,以免陷入困境。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-05-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-31
    相关资源
    最近更新 更多