按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!
lo
there being first。 The serial behavior is easy to understand for humans。 Things bee pli
cated when you need to think of multiple tasks at the same time。 While the puter has no
problem with threads; a human who is thinking in a serial manner codes the logic; and thus the
logic could be wrong。
Writing a good threading application should remind you of herding cats or dogs。 If you are
not careful with your threads and synchronization; then it is like herding ten cats into a single
corner—a nearly impossible task; since cats do not respond well to mands。 But if you are
careful and conscientious; then it is like herding ten dogs into a corner—fairly easy if the dogs
are trained。
Waiting for the Thread to End
Calling Start() will start a thread; causing a task to be executed。 The caller of the thread does
not wait for the created thread to end; because the created thread is independent of the caller。
So if you were running a batch process; you would need to wait until all threads have pleted。
The caller logic only needs to start the threads; and thus its work requires a fraction of the time
that the threads require。
There is a way for the caller thread to know when a created thread has exited。 This technique
involves using the Join() method; like this:
Sub ThreadWaitingTask()
Console。WriteLine(〃hello there〃)
Thread。Sleep(2000)
End Sub
…………………………………………………………Page 369……………………………………………………………
C HA P TE R 1 3 ■ L E AR N IN G AB O U T M U L T IT HR E AD IN G 347
Private Sub ThreadWaiting()
Dim thread As New Thread(AddressOf ThreadWaitingTask)
thread。Start()
thread。Join()
End Sub
The line at the end of the code calls the Join() method; which means that the thread calling
Join() is blocked until the thread referenced by the instance ends。 A Thread。Sleep() call is
used to put the other thread to sleep for the time specified by the parameter—2000 milliseconds; or
2 seconds; in this example。
This code solves the problem of the premature exit of the calling thread; but if the calling
thread is going to wait until the created thread exits; what’s the benefit? In this simple example;
using Join() adds no benefit。 However; when the caller thread executes many threads; the
caller wants to continue only when all threads have finished executing。 So in a multithreading
situation; you would want to call Join() on each and every thread。
Another variation of Join() is where a parameter specifies a timeout。 Imagine starting a
thread; and in the worst…case scenario; you predict a processing time of 5 minutes。 If the processing
time is exceeded; the logic is to forcibly exit the thread。 Here’s the code to implement that logic:
If Not thread。Join(300000) Then
thread。Abort()
End If
In the example; calling Join() will cause the executing thread to wait 300;000 milliseconds
(5 minutes) before continuing。 If the timeout occurred; the Join() method would return False;
and the code would forcibly exit the thread using the Abort() method。
■Note It is wise to avoid using Abort() except in the most dire of situations; because data will be corrupted。
Creating a Thread with State
In the threading example; the threads did not manage any state。 In most cases; your threads
will reference some state。
Implementing a ThreadStart Delegate
One way to run a thread with state is to define a type that implements a delegate of the type
ThreadStart。 The following example defines a class with a method that will be called by a thread。
The technique used is where a delegate from another class instance is passed to the Thread type。
Class ThreadedTask
Private whatToSay As String
Public Sub New(ByVal whattosay As String)
_whatToSay = whattosay
End Sub
…………………………………………………………Page 370……………………………………………………………
348 CH AP T E R 1 3 ■ L E A R N I N G A B OU T M U L T I TH R E A DI N G
Public Sub MethodToRun()
Console。WriteLine(〃I am babbling (〃 & _whatToSay & 〃)〃)
End Sub
End Class
To use the method; the threading code is changed as follows:
Dim task As ThreadedTask = New ThreadedTask(〃hello〃)
Dim thread As Thread = _
New Thread(AddressOf task。MethodToRun)
thread。Start()
In the example; the ThreadedTask type is instantiated with a state; and then Thread is
instantiated with the stateful task。MethodToRun() method。 When the thread starts; the data
member _whatToSay will have some associated state。 The code is logical and has no surprises。
But what if you were to use the stateful method twice; like this:
Dim task As ThreadedTask = New ThreadedTask(〃hello〃)
Dim thread1 As Thread = New Thread(AddressOf task。MethodToRun)
Dim thread2 As Thread = New Thread(AddressOf task。MethodToRun)
thread1。Start()
thread2。Start()
Here; there are two Thread instances; but a single task instance。 There will be two threads
doing the same thing; and even worse; two threads sharing the same state。 It is not wrong to
share state; but sharing state requires special treatment to ensure that state remains consistent。
You need to instantiate a single ThreadedTask and associate it with a single Thread instance;
like this:
Dim task1 As ThreadedTask = New ThreadedTask(〃hello〃)
Dim task2 As ThreadedTask = New ThreadedTask(〃goodbye〃)
Dim thread1 As Thread = New Thread(AddressOf task1。MethodToRun)
Dim thread2 As Thread = New Thread(AddressOf task2。MethodToRun)
thread1。Start()
thread2。Start()
If you are running a stateful method; you need to associate a task instance with a thread
instance。
Using a Thread Parameter
Suppose that you want to create a stateful thread。 You can do this by using a thread parameter。 In
other words; the method that you invoke on another thread takes a parameter。 Here’s an example:
…………………………………………………………Page 371……………………………………………………………
C HA P TE R 1 3 ■ L E AR N IN G AB O U T M U L T IT HR E AD IN G 349
Sub SimpleThreadWithStateTask(ByVal buffer As Object)
Console。WriteLine(〃You said (〃 & buffer。ToString() & 〃)〃)
End Sub
Private Sub SimpleThreadWithState()
Dim thread1 As New Thread(AddressOf SimpleThreadWithStateTask)
thread1。Start(〃my text〃)
End Sub
The major difference with a thread parameter is that you declare the function that is executed
with a parameter; and the Start() method has a parameter。
Two restrictions apply to using a thread parameter: you can send only a single parameter;
and that parameter must be an object。
Synchronizing Between Threads
When you have two threads and both share state (such as a variable); a concurrency situation
may arise。 Sharing state between two independent threads is not a problem if both threads
consider the data as read…only。 What does the reading thread read? Is the state consistent? It is
probably not consistent; and that is why you need to synchronize access to state。
Let’s conside