小牛电子书 > 其他电子书 > VB2008从入门到精通(PDF格式英文版) >

第130章

VB2008从入门到精通(PDF格式英文版)-第130章

小说: VB2008从入门到精通(PDF格式英文版) 字数: 每页3500字

按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!




               From a user perspective; it would seem obvious to call the method IncrementCounter()  

          directly from the other thread (_thread)。 However; hidden in the implementation of Invoke()  

          is a producer/consumer implementation。 The producer is the Invoke() method; which adds a  

          delegate that needs to be called to a queue。 The consumer is the Windows。Forms。Form class; which  

          periodically checks its Invoke() queue and executes the delegates contained within。 

               In a nutshell; a producer/consumer implementation is nothing more than a handoff of  

          information from one thread to another thread。 This is effective because the producer and  

          consumer are separate and manage their own concerns。 The only mon information  

          between the producer and consumer is a queue; or list; which is synchronized and contains  

          information of interest to both the producer and consumer。 



          Implementing a Generic Producer/Consumer Architecture 



          The architecture implemented by Windows。Forms is elegant and self…containing。 You can imple

          ment a generic producer/consumer architecture using a delegate; as shown in the following  

          source code。 In this case; we use the System。Action class; which encapsulates a Sub that doesn’t  

          take any parameters (it is shorthand for  Public Delegate Sub Action())。 


…………………………………………………………Page 387……………………………………………………………

                                                  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 365 



Imports System。Threading 



Class ThreadPoolProducerConsumer 



    Private _queue As Queue(Of Action) = New Queue(Of Action)() 



    Private Sub QueueProcessor(Byval obj As Object)  

        Monitor。Enter(_queue) 

        Do While _queue。Count = 0 

            Monitor。Wait(_queue; …1) 

        Loop 

        Dim action As Action = _queue。Dequeue() 

        Monitor。Exit(_queue) 

        ThreadPool。QueueUserWorkItem(AddressOf QueueProcessor) 

        action() 

    End Sub 



    Public Sub New() 

        ThreadPool。QueueUserWorkItem(AddressOf QueueProcessor) 

    End Sub 



    Public Sub Invoke(ByVal toExec As Action) 

        Monitor。Enter(_queue) 

        _queue。Enqueue(toExec) 

        Monitor。Pulse(_queue) 

        Monitor。Exit(_queue) 

     End Sub 

End Class 



     ThreadPoolProducerConsumer has a single public method; Invoke(); which is used in the  

same fashion as the Windows。Forms Invoke() method。 What makes the generic producer/consumer  

work is its use of the Monitor synchronization class。  

     To understand how Monitor works in the producer/consumer context; consider the overall  

producer/consumer implementation。 The consumer thread (QueueProcessor()) executes  

constantly; waiting for items in the queue (_queue)。 To check the queue; the Monitor。Enter()  

method is called; which says; “I want exclusive control for a code block that ends with the method  

call Monitor。Exit()。” To check the queue; a Do While loop is started。 The loop waits until there  

is something in the queue。 The thread could execute constantly; waiting for something to be  

added; but while the thread is looping; it has control of the lock。 This means a producer thread  

cannot add anything to the queue。 

     The consumer needs to give up the lock; but also needs to check if anything is available in  

the queue。 The solution is to call Monitor。Wait(); which causes the consumer thread to release  

the lock and say; “Hey; I’m giving up the lock temporarily until somebody gives me a signal to  

continue processing。” When the consumer thread releases its lock temporarily; it goes to sleep  

waiting for a pulse。 


…………………………………………………………Page 388……………………………………………………………

366       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 



               The producer thread (Invoke()) also enters a protected block using the Monitor。Enter()  

          method。 Within the protected block; an item is added to the queue using the Enqueue() method。  

          Because an item has been added to the queue; the producer thread sends a signal using the  

          Monitor。Pulse() method to indicate an item is available。 This will cause the thread that gave  

          up the lock temporarily (the consumer thread) to wake up。 However; the consumer thread  

          executes when the producer thread calls Monitor。Exit()。 Until then; the consumer thread is in  

          ready…to…execute mode。 

               In the simplest case of this implementation; a single thread would constantly execute  

          QueueProcessor()。 An optimization is to create and use a thread pool。 A thread pool is a collec

          tion of ready…to…execute threads。 As tasks arrive; threads are taken from the pool and used to  

          execute the tasks。 Once the thread has pleted executing; it is returned to the thread pool in  

          ready…to…execute mode。 In the ThreadPoolProducerConsumer constructor; the method ThreadPool。 

          QueueUserWorkItem() uses thread pooling to execute the method QueueProcessor()。 In the  

          implementation of QueueProcessor(); the method ThreadPool。QueueUserWorkItem() is called  

          again before calling the delegate。 The result is that one thread is always waiting for an item  

          in the queue; but there may be multiple threads executing concurrently; processing items from  

          the queue。 

               Using the generic producer/consumer is nearly identical to using the Windows。Forms  

          Invoke() method。 The following is a sample implementation。 



          Imports System。Threading 



          Public Class TestProducerConsumer  

              Delegate Sub TestMethod() 

               

              Sub Method()  

                  Console。WriteLine(〃Processed in thread id (〃 & _ 

                      Thread。CurrentThread。ManagedThreadId & 〃)〃) 

              End Sub 



              Public Sub TestSimple()  

                  Dim producer As ThreadPoolProducerConsumer = _ 

                    New ThreadPoolProducerConsumer() 

                  Console。WriteLine(〃Sent in thread id (〃 & _ 

                      Thread。CurrentThread。ManagedThreadId()& 〃)〃) 

                  producer。Invoke(AddressOf Method) 

              End Sub 

          End Class 



               The TestSimple() method instantiates the ThreadPoolProducerConsumer type。 Then the  

          Invoke() method is called using the delegate TestMethod; which executes the Method() method。  



          ■Note  The Thread。ManagedThreadId property uniquely identifies the managed thread to which it belongs。 


…………………………………………………………Page 389……………………………………………………………

                                                  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 367 



Using an Asynchronous Approach  



Using asynchronous techniques means to perform a task; such as read a file or database result;  

and then rather than wait for the results; let some other code handle the results。 The asynchro

nous interaction is an example of the producer/consumer architecture; where the consumer  

makes a request of the producer and carries on until it gets a response to that request。 

     The asynchronous technique used throughout the  API is consistent and is easily  

demonstrated by reading a file asynchronously。 In Chapter 10; you learned how to read a file or  

console stream using synchronous techniques。 You could just as well have read that file or  

stream asynchronously。 

     You would use asynchronous techniques when you don’t want to wait around for the task  

to plete。 To read a file asynchronously; the following source code is used。 



Imports System。IO 

Imports System。Text 



Friend Module TestAsynchronousFile 

    Dim dat

返回目录 上一页 下一页 回到顶部 2 2

你可能喜欢的