将参数传递给线程化的 LongRunningProcess





0/5 (0投票)
实现进度条并将参数传递给 LongRunningProcess。
引言
本文演示了创建新线程并将参数传递给 LongRunningProcess
的方法,同时在主线程上更新进度条。
背景
本文是 2011 年 5 月 4 日发表的同名文章的后续文章。原始文章是尝试寻找解决方案。当前文章是一个经过大约六个月测试的最终解决方案。
使用代码
代码略有抽象,但修改后应可针对特定过程的参数运行。在此示例中,该过程将 file1 加密为 file2,并需要三个额外的参数作为输入。如果未发生错误,则该过程返回 0;如果发生错误,则返回非零值。示例代码提供了一个取消按钮。此代码适用于非常大的文件,以及当过程不提供中间返回值来更新进度条时。代码分为两个类:一个主线程类和一个线程包装器,用于启动新线程并返回完成值。 另一个类包含一个用于获取文件哈希值的线程包装器。 这用于演示返回数据而不是整数完成值。
' This code example demonstrates implementing a progress bar for a long
' running process by creating a new thread for the process while
' updating the progress bar on the main thread. In this example the
' long running process is an API call that does not return until
' finished and returns an integer to indicate an error or success.
Option Strict Off
Option Explicit On
Imports VB = Microsoft.VisualBasic
Imports CryptoSysAPI
Imports System
Imports System.IO
Imports System.Threading
Public Delegate Sub CallbackToEnc(ByVal var1 As Integer)
Public Delegate Sub CallbackToHash(ByVal fileHash As String)
Public Class Protect
Public rtnBlfResult As Integer
Public Shared Sub ResultCallback(ByVal var1 As Integer)
CProtect.rtnBlfResult = var1
End Sub
' This function encrypts file1 to file2. This example is a much simplified version
' of an encrypter and does not include what is necessary to prepare file1 for
' encryption.
Public Function Encrypter(ByVal file1 As String, _
ByVal file2 As String, _
ByVal param1 As String, _
ByVal param2 As Integer, _
ByVal param3 As String) As Short
Dim iAbortLock As Boolean = False ' Do not allow more than one call to cancel.
Dim time1 As Single = 0
Dim time2 As Single = 0
' Create a new thread for encrypting file1 to file2 where the encryption is a
' long running process.
' Thread wrapper runs new thread tw1, while progress bar is updated on
' the main thread.
CProtect.rtnBlfResult = -2 ' Initialize return.
Dim tw1 As New TWrapEnc(file1, _
file2, _
param1, _
param2, _
param3, _
New CallbackToEnc(AddressOf ResultCallback))
tw1.start()
' Update progress bar until tw1 returns or cancel button is clicked.
T1: time2 = VB.Timer
If cancelBttnSequence = 3 Then ' Indicates the user has canceled.
' Allow one thread abort call and then wait for thread to stop.
If iAbortLock = False Then
tw1.thread.Abort()
iAbortLock = True
time1 = VB.Timer
End If
' If thread stopped, stop waiting.
If tw1.thread.ThreadState = System.Threading.ThreadState.Stopped _
Then GoTo T2
' If wait is more than 5 seconds, exit. Timer gets time since midnight.
If time1 > 0 And (VB.Timer - time1) > 5 Then GoTo T2a
' If midnight is spanned, elapsed time will be negative.
If (VB.Timer - time1) < 0 Then time1 = VB.Timer ' Midnight problem, time1.
End If
If (VB.Timer - time2) < 0 Then time2 = VB.Timer ' Midnight problem, time2.
' Update Progress Bar every 1 seconds.
While (VB.Timer - time2) < 1
' Synclock synchronizes writing and reading of rtnBlfResult.
SyncLock tw1.rtnLockEnc
If CProtect.rtnBlfResult = -1 Then GoTo T2
End SyncLock
End While
UpdatePgrBar() ' Update progress bar.
GoTo T1
T2: tw1.join() ' Process has completed and tw1 has returned.
' If T2a executes without T2 executing, rtnBlfResult will be as preset (-2).
' This will be interpreted as an error in code that follows.
T2a: tw1 = Nothing
rtnBlfResult = CProtect.rtnBlfResult
If rtnBlfResult = 0 Then
Encrypter = -1 ' Successfull, file2 contains encrypted form of file1.
ElseIf iAbortLock = True Then
Encrypter = -2 ' Cancel.
Else
Encrypter = 0 ' Error.
End If
End Function
Public Shared Sub UpdatePgrBar()
' Some code to update progress bar.
End Sub
End Class
' This class is the thread wrapper.
Public Class TWrapEnc
Private fileX1 As String
Private fileX2 As String
Private paramX1 As String
Private paramX2 As Integer
Private paramX3 As String
Private blfRtnParam As Integer = -1
Private callBack As CallbackToEnc
Public rtnLockEnc As New Object
Public thread As System.Threading.Thread
Public Sub New(ByVal file1 As String, _
ByVal file2 As String, _
ByVal param1 As String, _
ByVal param2 As Integer, _
ByVal param3 As String, _
ByVal callBackDelegate As CallbackToEnc)
fileX1 = file1
fileX2 = file2
paramX1 = param1
paramX2 = param2
paramX3 = param3
callBack = callBackDelegate
thread = New System.Threading.Thread(AddressOf body)
End Sub
Public Sub start()
Me.thread.Start()
End Sub
Public Sub join()
Me.thread.Join()
End Sub
Public Sub body()
On Error GoTo E1
' API call to encrypt fileX1 to fileX2.
Me.blfRtnParam = Blowfish.FileEncrypt(Me.fileX1, Me.fileX2, _
Me.paramX1, Me.paramX2, _
Me.paramX3)
E1: SyncLock rtnLockEnc
If Not callBack Is Nothing Then callBack(Me.blfRtnParam)
End SyncLock
' Wipe some params.
Me.fileX1 = ""
Me.fileX2 = ""
Me.paramX1 = ""
End Sub
End Class
' This class is the thread wrapper for getting hash of fileNameParam.
' There is no call to this class from the Protect Class in this example. The
' class is included to show the return of data instead of an integer return.
Public Class ThreadWrapperHash
Private fileNameParam As String
Private callback As CallbackToHash
Private fileHashRtnParam As String
Public rtnLockHash As New Object
Public thread As System.Threading.Thread
Public Sub New(ByVal fileName As String, _
ByVal callbackDelegate As CallbackToHash)
fileNameParam = fileName
callback = callbackDelegate
thread = New System.Threading.Thread(AddressOf Body)
End Sub
Public Sub start()
Me.thread.Start()
End Sub
Public Sub join()
Me.thread.Join()
End Sub
Public Sub Body()
On Error GoTo CallB
Me.fileHashRtnParam = Sha256.FileHexHash(Me.fileNameParam)
CallB: SyncLock rtnLockHash
If Not callback Is Nothing Then callback(Me.fileHashRtnParam)
End SyncLock
Me.fileNameParam = ""
End Sub
End Class
关注点
感谢 Marcus Kramer 和 SAKryukov 在我最初尝试解决此问题时提供的帮助。
历史
- 首次尝试的解决方案发表于 2011 年 5 月 4 日。