Monitor。Wait(elements; 1000) Loop items = elements。ToArray() Monitor。Exit(elements) Dim item As Integer For Each item In items Console。WriteLine(〃Item (〃 & item & 〃)〃) Thread。Sleep(1000) Next End Sub Sub Task2() Monitor。Enter(elements) elements。Add(30) Monitor。Pulse(elements) Monitor。Exit(elements) End Sub The bolded code lines are the new pieces that use the Monitor type。 In the definition of the first thread to get the lock; the Monitor。Enter() method is called with the parameter elements; which; as in the earlier SyncLock example; defines the lock reference handle。 Once the lock has been acquired; the thread checks to see if the list count is greater or equal to 3。 If the counter is less than 3; the Monitor。Wait() method is called。 The behavior of Monitor。Wait() is similar to Thread。Sleep(); except that the Monitor lock is given up。 Releasing the lock is a unique feature of a Monitor。 The lock is given up only during the time that the caller is in Monitor。Wait()。 When the Monitor。Wait() method returns; the lock is acquired again。 The code says that the thread is reawakened after 1 second。 After that second; the thread does not have the lock and needs to wait before it can acquire the lock。 If another thread is holding onto the lock for a long time; it could take a while to get the lock back again。 Another way for the Monitor。Wait() method to awaken is if a signal is sent by another thread。 The code for the second thread uses Enter() and Exit(); but also Pulse()。 The Monitor。 Pulse() method triggers a signal that awakens the first thread; but the first thread will execute only after the second thread has released control of the lock。 The big advantages of a Monitor in parison to SyncLock are that the Monitor can be used anywhere in the code and that the Monitor will release a lock while waiting for an answer。 You would use SyncLock when you want to control access to a block of code。 If the access goes beyond method boundaries; then it is preferable to use Monitor。 It is not that you could not use a SyncLock that spanned boundaries; but if you need to add code that could produce a dead lock; it is easier to control that code using a Monitor。 Now that we’ve covered the fundamentals of multithreading; the next sections focus on more advanced threading architectures—reader/writer and producer/consumer—and using asynchronous calls。 …………………………………………………………Page 381…………………………………………………………… 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 359 Implementing a Reader/Writer Threaded Architecture The reader/writer threaded architecture is based on the idea that if one thread is reading and another thread would like to read as well; why not let it? However; if one thread wants to write; then only that thread can write。 In other words; multiple threads are allowed to read data simultaneously; but to write; a thread must have an exclusive lock。 implements a System。Threading。ReaderWriterLock class; which contains the reader/ writer functionality。 This class is like a Monitor; in that it gives you the control to manage how data is accessed but does not determine what you are accessing。 The ReaderWriterLock type has a number of methods and properties。 The most important ones are listed in Table 13…1。 Table 13…1。 Important ReaderWriterLock Methods Method Description AcquireReaderLock() Acquires a reader lock。 Multiple threads can acquire a reader lock。 AcquireWriterLock() Acquires a writer lock。 Only a single thread can acquire a writer lock。 DowngradeFromWriterLock() Converts a writer lock into a reader lock。 Using this method avoids the need to call ReleaseWriterLock() and AcquireReaderLock()。 UpgradeToWriterLock() Converts a reader lock into a writer lock。 Using this method avoids the need to call ReleaseReaderLock() and AcquireWriterLock()。 ReleaseLock() Releases all locks; regardless how many times you have called to acquire the reader or writer locks。 ReleaseReaderLock() Decrements the reader lock a single count。 To pletely release a reader lock; you need to make sure the number of times you called ReleaseReaderLock() is equal to the number of times you called AcquireReaderLock()。 ReleaseWriterLock() Decrements the writer lock a single count。 To pletely release a reader lock; you need to make sure the number of times you called ReleaseWriterLock() is equal to the number of times you called AcquireWriterLock()。 Let’s look at a collection example that ha