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 data As Byte() = New Byte(200000) {} Private filename As String = 〃threads。vb〃 Public Sub RunAll() TestAsynchronousFile。LoadFileAsynchronously() End Sub Private Sub LoadFileAsynchronously() Dim fs As New FileStream(TestAsynchronousFile。filename; FileMode。Open) fs。BeginRead(Data ; 0; Data 。Length; _ AddressOf DoAsyncRead; fs)。AsyncWaitHandle。WaitOne() End Sub Sub DoAsyncRead(ByVal result As IAsyncResult) Dim localFS As FileStream = DirectCast(result。AsyncState; FileStream) Dim bytesRead As Integer = localFS。EndRead(result) Dim buffer As String = Encoding。ASCII。GetString(data) Console。WriteLine(〃Buffer bytes read (〃 & bytesRead & 〃)〃) localFS。Close() End Sub End Module To read a file; you need to open a file stream; just as in Chapter 10’s examples。 However; instead of reading the data directly; the BeginRead() method is called; and it starts a read operation。 What distinguishes the asynchronous operation is that BeginRead() returns immediately。 Think of it as starting the producer。 When you call BeginRead(); the first three parameters represent the variable that contains the read bytes。 The first parameter is the byte array where the data should be written。 The second and third parameters are the starting and ending locations of the write operation in the byte array。 The fourth parameter to BeginRead() is the delegate that will be called when the data is ready to be processed。 The last parameter is like a thread parameter and is assigned to the …………………………………………………………Page 390…………………………………………………………… 368 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 IAsyncResult。AsyncState data member。 IAsyncResult is in the System namespace and is there fore part of the API。 When you call BeginRead(); you are saying; “Please fill up as many bytes as possible in the byte array。 When you have read the bytes; call my consumer code。” The filling of the array and calling of the consumer code occur in a separate thread。 For illustration purposes; the AsyncWaitHandle。WaitOne() method is called so that the main calling thread continues only after the data has been read and processed。 It is a superfluous method call; since doing this would make the file…reading behavior resemble a synchronous operation。 The consumer code (that is; the DoAsyncRead() method)is executed on another thread and is responsible for reading all the bytes。 The method receives an IAsyncResult parameter; which has an AsyncState property and is the value that we passed in as the fifth parameter to BeginRead() (the file stream)。 DoAsyncRead() then converts this parameter into a FileStream and reads the remaining bytes from the stream。 The byte stream is then converted into a string buffer。 When all the data has been read; the file stream is closed。 When using this asynchronous approach; you are really writing producer/consumer code。 The use of IAsyncResult; BeginRead(); and EndRead() is quite mon。 The purpose of the asynchronous interface is to convert a synchronous operation into an asynchronous operation。 The Important Stuff to Remember In this chapter; you learned the essentials of using threads and how to write multithreaded code。 The main items to remember are as follows: o The operating system assigns time slices to your application。 o A time slice is a predefined amount of time in which your program can execute and has full control of the microprocessor。