|
|||||||||||||||||||||
|
|||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
Introduction
The Another added feature is that BackgroundIf you just want the So why use threading? One reason may be because you want to be able to press a button on the form while the form is busy but it won't let you because it's busy. The old VB6 way of doing this is to use a Another reason is that with dual/multi core processing now available and true multitasking at the hardware and operating system level, threading is going to be hard to avoid, especially when performance is a concern and your application is processor intensive. Okay, so you have decided you want to do threading in .NET. You could use the So what is a thread anyway? Simply put, it is the equivalent to another completely separate program that is initiated from your main program. Once a thread is started, the main program does not know anything about the thread (or threads); they are effectively separate programs in their own right. So some of the first things you may want to know are how to create them, how to pass data between them, how to call the main application from a thread and finally, how does the main application know which thread has called it? Viewing the code snippets below should help answer these questions. One final point before we start, using threads to copy files is not necessarily the best application of multithreading as copying files is disk I/O intensive rather than processor intensive. But it's still a fair use as counting files and copying files can occur asynchronously rather than synchronously, so why wait? And besides that, I think Using the CodeThis description of the code will not discuss the finer points of how to copy files but simply show the relevant source code to create the threads and use them from the main form application; showing how the threads are created and how parameters can be passed from the threads to the main Windows forms application. First, take a quick look at the imported namespaces in the Imports System.Threading
Imports System.IO
Imports System.Diagnostics.Process
The The next code snippet from the Imports System.Windows
Public Class Backup
' Declare the FileCopy class.
' This class will create 3 threads to copy, count and mirror files
' and raise events for each, so the events must be handled
' to update the form with status data.
Dim WithEvents CopyFiles As FileCopy
Private Sub StartCopy_Click(ByVal sender As System.Object, e As System.EventArgs) _
Handles StartCopy.Click
' Create the FileCopy class which will initiate the threads
CopyFiles = New FileCopy
' Initiate the copy, count and mirror threads from the FileCopy class
CopyFiles.StartCopy()
End Sub
.
. remaining forms code
.
End Class
Pressing the So far, all we have done in the main Windows form is declare as class, instantiate it, and then execute the And where is the code that declares the threads and starts them? Well, the very important point I am trying to make here, is that if you want to use threads, then it's best to create a class and use that class to start the threads. This is because the class can raise events whenever the threads it initiates need to communicate with the parent thread. This might seem obvious for the well rehearsed (and the arrogant) , but it's a very important design consideration, i.e. use a class to start threads. Okay, now let's look at the Imports System.IO
Public Class FileCopy
' Declares the variables you will use to hold your thread objects.
Public CopyThread As System.Threading.Thread
Public CountThread As System.Threading.Thread
Public MirrorThread As System.Threading.Thread
Public Sub StartCopy()
' Sets the copy and count threads using the AddressOf the subroutine where
' the thread will start.
CopyThread = New System.Threading.Thread(AddressOf Copy)
CopyThread.IsBackground = True
CopyThread.Name = "Copy"
CopyThread.Start()
CountThread = New System.Threading.Thread(AddressOf Count)
CountThread.IsBackground = True
CountThread.Name = "Count"
CountThread.Start()
End Sub
.
. code for the rest of the class
.
End Class
Pretty simple huh? Declare the threads and then have a method start them. So far, so good. But now that we have started the If you note the use of the Let's look quickly by expanding the Imports System.IO
Public Class FileCopy
' Declare the events that will be raised by each thread
Public Event CopyStatus(ByVal sender As Object, ByVal e As BackupEventArgs)
Public Event CountStatus(ByVal sender As Object, ByVal e As BackupEventArgs)
Public Event MirrorStatus(ByVal sender As Object, ByVal e As BackupEventArgs)
' Declares the variables you will use to hold your thread objects.
Public CopyThread As System.Threading.Thread
Public CountThread As System.Threading.Thread
Public MirrorThread As System.Threading.Thread
' Class variables' Class variables
Private _filePath As String
Private _fileSize As String
Private _copiedFolders As Long
Private _copiedFiles As Long
Private _countedFolders As Long
Private _countedFiles As Long
Private _mirroredFolders As Long
Private _mirroredFiles As Long
.
. even more class variables but we will just show the relevant ones.
.
Public Sub StartCopy()
' Sets the copy and count threads using the AddressOf the subroutine where
' the thread will start.
CopyThread = New System.Threading.Thread(AddressOf Copy)
CopyThread.IsBackground = True
CopyThread.Name = "Copy"
CopyThread.Start()
CountThread = New System.Threading.Thread(AddressOf Count)
CountThread.IsBackground = True
CountThread.Name = "Count"
CountThread.Start()
End Sub
Private Sub Copy()
.
. this is a program loop with logic to copy files
.
Loop to Copy Files
Copy a file here
' Raise the copy status event at the end of the program loop
RaiseEvent CopyStatus(Me, New BackupEventArgs_
("", 0, _copiedFiles, _copiedFolders))
Threading.Thread.Sleep(1)
End Loop
End Sub
Private Sub Count()
.
. this is a program loop with logic to count files
.
Loop to Count Files
Count a file here
' Raise the count status event at the end of the program loop
RaiseEvent CountStatus(Me, New BackupEventArgs_
("", 0, _countedFiles, _countedFolders))
Threading.Thread.Sleep(1)
End Loop
End Sub
.
. code for the rest of the class
.
End Class
So, there you have it. A basic class declaration that starts threads and raises events whenever it needs to communicate with the main parent thread, (which we know is the Note the use of We now need to look at the main parent thread (the First, take note the For now, just consider that the So, let's focus back on the parent thread, and let's see the code that deals with the events: Imports System.Windows
Public Class Backup
' Declare the FileCopy class. This class will create 3 threads to copy,
' count and mirror files
' and raise events for each, so the events must be handled to update
' the form with status data.
Dim WithEvents CopyFiles As FileCopy
' Declare delegate handlers for the copy and count events
Public Delegate Sub CopyHandler(ByVal FilePath As String, _
ByVal FileSize As Long, ByVal FileCount As Long)
Public Delegate Sub CountHandler(ByVal FileCount As Long, ByVal FolderCount As Long)
.
. more declarations
.
Private Sub StartCopy_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles StartCopy.Click
' Create the FileCopy class which will initiate the threads
CopyFiles = New FileCopy
' Initiate the copy, count and mirror threads from the FileCopy class
CopyFiles.StartCopy()
End Sub
Private Sub CopyStatus(ByVal FilePath As String, ByVal FileSize As Long, _
ByVal FileCount As Long)
.
. some code to update the forms display
.
End Sub
Private Sub CopyFiles_CopyStatus(ByVal sender As Object, _
ByVal e As BackupEventArgs) Handles CopyFiles.CopyStatus
' BeginInvoke causes asynchronous execution to begin at the address
' specified by the delegate. Simply put, it transfers execution of
' this method back to the main thread. Any parameters required by
' the method contained at the delegate are wrapped in an object and
' passed.
Me.BeginInvoke(New CopyHandler(AddressOf CopyStatus), _
New Object() {e.FilePath, e.FileSize, e.FileCount})
End Sub
.
. remaining forms code
.
End Class
The code snippet above has a In the code above, the specified delegate is If I have left you confused, just consider that although it looks like the Moving on, (for those still with me), just a couple of pointers that will help if you are new to threading. If we revise the One problem (challenge actually) I had was that I needed to make the copy thread wait for the count thread to complete before it (the copy thread) terminates naturally (i.e. finishes copying files). You would expect the count thread to finish first, but when there are no files to copy, sometimes the copy thread finished first! Using the Imports System.IO
Public Class FileCopy
' Declare the events that will be raised by each thread
Public Event CopyStatus(ByVal sender As Object, ByVal e As BackupEventArgs)
Public Event CountStatus(ByVal sender As Object, ByVal e As BackupEventArgs)
Public Event MirrorStatus(ByVal sender As Object, ByVal e As BackupEventArgs)
' Declares the variables you will use to hold your thread objects.
Public CopyThread As System.Threading.Thread
Public CountThread As System.Threading.Thread
Public MirrorThread As System.Threading.Thread
' Class variables' Class variables
Private _filePath As String
Private _fileSize As String
Private _copiedFolders As Long
Private _copiedFiles As Long
Private _countedFolders As Long
Private _countedFiles As Long
Private _mirroredFolders As Long
Private _mirroredFiles As Long
.
. even more class variables but we will just show the relevant ones.
.
Public Sub StartCopy()
' Sets the copy and count threads using the AddressOf the subroutine where
' the thread will start.
CopyThread = New System.Threading.Thread(AddressOf Copy)
CopyThread.IsBackground = True
CopyThread.Name = "Copy"
CopyThread.Start()
CountThread = New System.Threading.Thread(AddressOf Count)
CountThread.IsBackground = True
CountThread.Name = "Count"
CountThread.Start()
End Sub
Private Sub Copy()
.
. this is a program loop with logic to copy files
.
Loop to Copy Files
Copy a file here
' Raise the copy status event at the end of the program loop
RaiseEvent CopyStatus(Me, New BackupEventArgs_
("", 0, _copiedFiles, _copiedFolders))
Threading.Thread.Sleep(1)
End Loop
' After all files have been copied, cause this CopyThread to wait
' until CountThread has finished
If CountThread.IsAlive Then CountThread.Join()
End Sub
Private Sub Count()
.
. this is a program loop with logic to count files
.
Loop to Count Files
Count a file here
' Raise the count status event at the end of the program loop
RaiseEvent CountStatus(Me, New BackupEventArgs_
("", 0, _countedFiles, _countedFolders))
Threading.Thread.Sleep(1)
End Loop
End Sub
.
. code for the rest of the class
.
End Class
And one final pointer. How do you terminate a thread? Using the The code snippet below shows a method called Public Class FileCopy
.
. class code
.
Public Sub StopThreads()
_stopNow = True
End Sub
.
. more class code
.
.
Private Sub Copy()
While Loop to copy files
If _stopNow Then
Exit While
End If
copy a file
raise an event to notify parent thread
End While
End Sub
.
.
.
End Class
Points of InterestMuch of the code above was developed by copying and adapting code from the MSDN. So if you really want to get into the finer points of threading, there are some very fine examples that have been well explained at msdn.microsoft.com. I must say that the MSDN is finally improving to the point where it's hard not to be impressed. Some of the articles there even discuss best practice at length with some very fine walkthroughs. So a very special thanks to the coding gurus at MSDN. And finally, in saying goodbye and thank you to those that have managed to read this far, please vote for my article, be generous and you will be rewarded in kind. HistoryOctober 2007Uploaded version 1.0.7 which contained bug fixes as well as added a batch mode for running without a form and processing command line parameters. June 2008Uploaded version 2.0.0 which is a complete revision of the source code and this article, also added a help file and a mirror copy feature. July 2008Uploaded version 2.1.0 which has a new mini status bar as well as some fixes to some faults that may surface in version 2.0.0. So please upgrade. Also note that so far Backup has not been tested on Windows Vista. You may try it on Vista and, if there are problems, check back here periodically as there should be another release over the next few months that will be tested on Vista. Upgrading to the Latest VersionIf upgrading from a previous version, please uninstall the previous version first. Do this from the Control Panel (Start/Control Panel) by double clicking the Add/Remove Programs icon and selecting Using the Latest Source CodeThe source code for | ||||||||||||||||||||