使用互斥多线程时,在 Form1 上更新进度条

问题描述 投票:0回答:0

我正在尝试在将数据写入 MS Access 数据库时更新进度条。为了使写入数据库的速度更快。我已将数据表中的数据分成 1000 行的批次,总共大约有 8500 行。然后批处理使用 Mutex 线程方法来加快处理速度。

我目前在 Form1 上有一个启动写入数据过程的按钮。

Private Sub PrepareData_Click(sender As Object, e As EventArgs) Handles PrepareData.Click
        PrepareData.BackColor = Color.SlateGray
        Data_Preperation_Tasks()
End Sub

对于上下文,也会出现这种情况,

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        'Initialize the BackgroundWorker
        bgWorker.WorkerReportsProgress = True
        bgWorker.WorkerSupportsCancellation = True
        bgWorker.RunWorkerAsync()
End Sub
Private Sub bgWorker_ProgressChanged(sender As Object, e As ProgressChangedEventArgs) Handles bgWorker.ProgressChanged
        If Me.InvokeRequired Then
            Me.Invoke(Sub()
                          Me.ProgressBar1.Value = e.ProgressPercentage
                      End Sub)
            Return
        Else
            ProgressBar1.Value = e.ProgressPercentage
            ProgressBar1.Refresh()
        End If
End Sub

然后调用子:

Private Sub Data_Preperation_Tasks()
    'other code here that checks things

          Call Write_ProductDetails_ToDatabase_MutexMethod()
End Sub

以上是公开课Form 1 Write_ProductDetails_ToDatabase_MutexMethod() 在 Module1 里面

Module Module1

 Private Sub UpdateProgressBar(ByVal value As Integer)
        If Form1.IsHandleCreated Then
            Form1.Invoke(Sub()
                             Form1.ProgressBar1.Value = value
                             Form1.ProgressBar1.Refresh()
                         End Sub)
        Else
            Form1.ProgressBar1.Value = value
            Form1.ProgressBar1.Refresh()
        End If
    End Sub

    Sub Write_ProductDetails_ToDatabase_MutexMethod()

        Form1.Action3.Text = "Writing Product Details To Database"
        Form1.Action3.BackColor = Color.Orange
        Form1.Action3.Visible = True

        Dim sAppPath As String
        sAppPath = System.Windows.Forms.Application.StartupPath

        Dim connectionString As String = "PROVIDER=Microsoft.Jet.OLEDB.4.0;Data Source=" & sAppPath & "\BatchNumberUpload.MDB"
        Dim mutexName As String = "database_mutex"
        Dim mutex As Mutex = New Mutex(False, mutexName)

        Dim batchSize As Integer = 1000
        Dim threadCount As Integer = (InventoryTable.Rows.Count + batchSize - 1) \ batchSize ' Round up to the nearest integer
        Dim countdownEvent As CountdownEvent = New CountdownEvent(threadCount)

        Dim rowCount As Integer = 0 ' Keep track of the number of rows that have been written so far
        Dim totalRowCount As Integer = InventoryTable.Rows.Count

        Form1.ProgressBar1.Minimum = 0
        Form1.ProgressBar1.Maximum = totalRowCount
        Form1.ProgressBar1.Visible = True
       
        'Start the BackgroundWorker
        Form1.bgWorker.RunWorkerAsync()

        For i As Integer = 0 To InventoryTable.Rows.Count - 1 Step batchSize
            Dim batchRows = InventoryTable.Rows.Cast(Of DataRow)().Skip(i).Take(batchSize)

            ' Create a new thread for each batch of rows
            Dim thread = New Thread(Sub()
                                        ' Synchronize access to the database connection using a Mutex
                                        mutex.WaitOne()
                                        Try
                                            Using connection = New OleDbConnection(connectionString)
                                                Using command = New OleDbCommand()
                                                    command.Connection = connection
                                                    connection.Open()

                                                    For Each row In batchRows
                                                        Dim constring As String = "PROVIDER=Microsoft.Jet.OLEDB.4.0;Data Source=" & sAppPath & "\BatchNumberUpload.MDB"

                                                        Using con As New OleDbConnection(constring)

                                                            Using cmd As New OleDbCommand("INSERT INTO " & "`" & "BatchNumbers" & "`" & " Values(@BatchNumber,@ProductCode,@FirstLine,@SecondLine,@RRP,@SalePrice,@SaleEndDate,@Barcode)", con)


                                                                cmd.Parameters.AddWithValue("@BatchNumber", row.Item("BatchNumber"))
                                                                cmd.Parameters.AddWithValue("@ProductCode", row.Item("ProductCode"))
                                                                cmd.Parameters.AddWithValue("@FirstLine", row.Item("FirstLine"))
                                                                cmd.Parameters.AddWithValue("@SecondLine", row.Item("SecondLine"))
                                                                cmd.Parameters.AddWithValue("@RRP", row.Item("RRP"))
                                                                cmd.Parameters.AddWithValue("@SalePrice", row.Item("SalePrice"))
                                                                cmd.Parameters.AddWithValue("@SaleEndDate", row.Item("SaleEndDate"))
                                                                cmd.Parameters.AddWithValue("@Barcode", row.Item("Barcode"))
                                                                con.Open()

                                                                cmd.ExecuteNonQuery()

                                                                con.Close()

                                                            End Using

                                                        End Using
                                                        rowCount += 1 ' Increment the number of rows that have been written so far
                                                        If rowCount Mod 10 = 0 Then
                                                            Dim progressPercentage As Integer = CInt(rowCount * 100 / totalRowCount)
                                                            Form1.bgWorker.ReportProgress(progressPercentage) ' Report progress to the background worker
                                                        End If

                                                    Next
                                                End Using
                                            End Using
                                        Finally
                                            mutex.ReleaseMutex()
                                            countdownEvent.Signal() ' Signal that the thread has completed
                                        End Try
                                    End Sub)
            thread.Start()
        Next

        ' Wait for all threads to complete before proceeding to the next subroutine
        countdownEvent.Wait()

        UpdateProgressBar(totalRowCount)

        Form1.Action3.Text = "Completed Writing To Database"
        Form1.Action3.BackColor = Color.LimeGreen
        Form1.Action3Tick.Visible = True

        Form1.TimeRemaining.Text = "Completed"

    End Sub



End Module

我的问题是无论我尝试什么,我都无法让 ProgressBar1 回到 Form1 上以更新/重绘以显示它已经取得进展。 它会在 countdownEvent.Wait() 发生后最后更新。

在这些踏板运行时,窗体及其所有控件也没有响应。我有点理解为什么,并且这些线程没有在 UI 线程上运行。

但是有没有办法让进度条在运行时更新,或者甚至保持表单响应以便最小化?从示例中,如果在 stackoverflow 上看到我无法开始工作。

vb.net multithreading progress-bar mutex
© www.soinside.com 2019 - 2024. All rights reserved.