按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!
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。
o To implement tasks that you want to run separately from the main program; you
use threads。
o Each program that is started is a task and has a main thread from which you can start
other threads。
o Threading is not difficult and easily implemented。 What is more difficult is synchroniza
tion between the threads。
o Synchronization is not about the data; but about synchronizing access to code that
modifies data that is shared。 If your data is not shared; you don’t need synchronization。
o In the context of a single application; you will use either the exclusive lock or the Monitor
for synchronization。
o Locking code slows down the code。 You should keep the locks for the shortest time possible。
o To improve throughput; you can take a snapshot of the data。
o Higher…level synchronization abstractions are the reader/writer and producer/consumer
architectures。
…………………………………………………………Page 391……………………………………………………………
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 369
o Reader/writer locks are exclusive locks; but they separate code that reads from code
that writes。 To improve code efficiency; reader/writer locks allow multiple readers; but
only a single writer。 Reader/writer locks are effective only if; for the most part; you are
reading data。
o Producer/consumer locks split the task of producing and consuming data into two sepa
rate steps。 The API uses the producer/consumer concept extensively; examples are
Windows。Forms and IAsyncResult。
o Deadlocks occur because timing changes cause your code to not be deterministic。
o Deadlocks can be partially avoided using Monitors; but the most effective way of avoiding
deadlocks is to use the producer/consumer development technique。 This is because the
producer/consumer architecture takes the approach of handing off data; rather than
sharing data。
o Applications that multitask effectively are applications that have been designed using
logic; rather than development techniques where you think up the code as you go along。
Some Things for You to Do
The following is an exercise to help you apply what you learned in this chapter。
1。 Write a general architecture that generates a series using multiple threads。 For the first
series; generate the square of all numbers between 1 and 100。 For the second series;
generate the Fibonacci series。 That is; after two starting values; each number is the sum
of the two preceding numbers。 The first Fibonacci numbers are 0; 1; 1; 2; 3; 5; 8; 13; 21;
34; 55; 89; 144; 233; 377; 610; 987; 1597; 2584; 4181; 6765; 10946; 17711; 28657; 46368;
75025; 121393; 196418; and 317811。 Outline the limits of multithreading when generating
a series。
…………………………………………………………Page 392……………………………………………………………
…………………………………………………………Page 393……………………………………………………………
C H A P T E R 1 4
■ ■ ■
Learning About Relational
Database Data
Literally hundreds of techniques; tips; tricks; and libraries are associated with relational data
bases。 Covering relational databases would take an entire a book; and in fact; many books are
devoted to that subject。 This chapter will cover the basics and give you enough knowledge to
read and write to a database。
The focus of this chapter is to demonstrate accessing relational databases with ADO
and the Visual Studio Dataset Designer。 Since we’ll need a database to