按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!
SyncLock elements
Do While (elements。Count 《 3)
Thread。Sleep(1000)
Loop
items = elements。ToArray()
End SyncLock
Dim item As Integer
For Each item In items
Console。WriteLine(〃Item (〃 & item & 〃)〃)
Thread。Sleep(1000)
Next
End Sub
Sub Task2()
Thread。Sleep(1500)
SyncLock elements
elements。Add(30)
End SyncLock
End Sub
Sub Main()
elements。Add(10)
elements。Add(20)
Dim thread1 As New Thread(AddressOf Task1)
Dim thread2 As New Thread(AddressOf Task2)
thread1。Start()
thread2。Start()
End Sub
End Module
The iteration code waits until the collection count is 3。 However; this never happens; because
the thread that could make the collection count 3 is waiting for the lock to bee free。 The
bolded code is the waiting code that queries whether the collection count is 3。 If it is not; the
thread waits for 1 second and asks again。 But throughout all of this waiting; the lock is never given
up; and thus the second thread that could add an element is waiting。 The code will deadlock。
Without modifying the locks; here is a tweak that will avoid the deadlock (the thread sleeps for
only 0。5 seconds instead of 1。5 seconds; so the writing thread can get in first before the reader
thread gets in):
Sub Task2()
Thread。Sleep(500)
SyncLock elements
elements。Add(30)
End SyncLock
End Sub
…………………………………………………………Page 379……………………………………………………………
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 357
The single change (shown in bold) makes the code work。 In the first version; the timing
of the code was such that the reading thread went first。 In this version; the writing thread goes
first。 This shows that deadlocks are often timing…related。
The annoying part of deadlocks is that your code’s behavior is not deterministic。 Determin
istic behavior is when an action will result in a single result; as in the case with most source
code。 Typically; when you have a bug; you didn’t think far enough ahead and can work through
the error systematically。 However; with threading; your code ceases to be deterministic; because
timing can change the behavior。 Timing can be an influence in many ways: resource swapping;
debuggers; microprocessor speed; and a host of other features。
To make the code deterministic; you need to fix the part of the code that hung onto the lock
when it should not have。 Remember the cardinal rule: keep a lock for as short a time as possible。
You need to use a more advanced lock construct that allows you to wait for data to bee
available。 has quite a few constructs related to threading and synchronization; and each
construct is specific to the type of problem you are trying to solve。 In the case of a deadlock; you
want to use the Monitor type。 The Monitor type is an advanced synchronization type that allows
locking and pulsing of trigger signals for those threads that are waiting。
Let’s return to our multiple cooks in the kitchen analogy。 Say one cook needs a particular
fish pan; which is already being used by another cook。 Does the waiting cook tap her foot beside
the cook doing the cooking? Or does the waiting cook do something else and ask the cook using
the pan to inform her when the pan is free? Most likely; the cook will do something else and
wait to be informed that the pan is free。
This concept of working together and being able to notify other lock users is a powerful
feature programmed into the Monitor type。 Monitor has the ability to take a lock; give it up so
others can get the lock; and then take it back again。
When using the Monitor type; you do not declare a block of code that is protected; because
Monitor is much more flexible than that。 For example; you could define a class that has an
instance…level lock mechanism; like this:
Class DoSomething
Public Sub GetLock()
Monitor。Enter(Me)
End Sub
Public Sub ReleaseLock()
Monitor。Exit(Me)
End Sub
End Class
Any code that uses a Monitor is not restricted to where it’s placed in the code; but a Monitor
is bound to a thread。 So if a thread grabs a Monitor (by calling the Enter() method on the
Monitor object); it has control until the thread dies or the thread gives up control (by calling the
Exit() method on the Monitor object)。 This has the added benefit that; once having acquired a
lock; a Monitor can get it over and over again。 However; if the same thread locked the Monitor
five times; the same thread needs to release it five times before another thread can be granted
access to the lock。
The following is the rewritten two…thread source code that uses a Monitor。
…………………………………………………………Page 380……………………………………………………………
358 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
Sub Task1()
Dim items As Integer()
Thread。Sleep(1000)
Monitor。Enter(elements)
Do While (elements。Count 《 3)
Monitor。Wait(elements; 1000)
Loop