提问人:Andy Andromeda 提问时间:3/25/2023 最后编辑:Ken WhiteAndy Andromeda 更新时间:3/25/2023 访问量:41
使用 Mutex Multithread 时更新 Form1 上的进度条
Update Progress bar on Form1, when using a Mutex Multithread
问:
我正在尝试在将数据写入 MS Access 数据库时更新进度条。为了更快地写入数据库。我已将数据表中的数据分解为 1000 行,总共大约有 8500 行。然后,批处理使用互斥线程方法来加快该过程。
我目前在 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
然后调用 sub:
Private Sub Data_Preperation_Tasks()
'other code here that checks things
Call Write_ProductDetails_ToDatabase_MutexMethod()
End Sub
以上字幕属于公开课表格 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
我的问题是无论我尝试什么,我都无法在 Form1 上恢复 ProgressBar1 以更新/重绘以显示它已经进展。 它将在发生 countdownEvent.Wait() 之后的末尾更新。
此外,当这些踏板运行时,窗体及其所有控件都无响应。我有点理解为什么,并且这些线程没有在 UI 线程上运行。
但是,有没有办法在运行时更新进度条,甚至保持表单响应,以便将其最小化?从示例中,如果在stackoverflow上看到,我无法开始工作。
答: 暂无答案
评论
SynchronizationContext