[ Pobierz całość w formacie PDF ]
.Every thread that reads from this memory must first call theBeginRead method.BeginRead ensures that no other thread is currently writing to thememory.When a thread finishes reading the protected memory, it calls the EndReadmethod.Any thread that writes to the protected memory must call BeginWrite first.BeginWrite ensures that no other thread is currently reading or writing to thememory.When a thread finishes writing to the protected memory, it calls theEndWrite method, so that threads waiting to read the memory can begin.Warning Like critical sections, the multi-read exclusive-write synchronizer only works if everythread uses it to access the associated global memory.Threads that ignore thesynchronizer and access the global memory without calling BeginRead or BeginWriteintroduce problems of simultaneous access.Other techniques for sharing memoryWhen using objects in the VCL, use the main VCL thread to execute your code.Usingthe main VCL thread ensures that the object does not indirectly access any memorythat is also used by VCL objects in other threads.See Using the main VCL threadon page 7-4 for more information on the main VCL thread.If the global memory does not need to be shared by multiple threads, consider usingthread-local variables instead of global variables.By using thread-local variables,your thread does not need to wait for or lock out any other threads.See Usingthread-local variables on page 7-5 for more information about thread-localvariables.Waiting for other threadsIf your thread must wait for another thread to finish some task, you can tell yourthread to temporarily suspend execution.You can either wait for another thread tocompletely finish executing, or you can wait for another thread to signal that it hascompleted a task.Waiting for a thread to finish executingTo wait for another thread to finish executing, use the WaitFor method of that otherthread.WaitFor doesn t return until the other thread terminates, either by finishingits own Execute method or by terminating due to an exception.For example, thefollowing code waits until another thread fills a thread list object before accessing theobjects in the list:if (pListFillingThread->WaitFor()){for (TList *pList = ThreadList1->LockList(), int i = 0; i Count; i++)ProcessItem(pList->Items[i]);ThreadList1->UnlockList();}In the previous example, the list items were only accessed when the WaitFor methodindicated that the list was successfully filled.This return value must be assigned by7-8 Dev el oper s Gui deCo o r d i n a t i n g t h r e a d sthe Execute method of the thread that was waited for.However, because threads thatcall WaitFor want to know the result of thread execution, not code that calls Execute,the Execute method does not return any value.Instead, the Execute method sets theReturnValue property.ReturnValue is then returned by the WaitFor method when it iscalled by other threads.Return values are integers.Your application determines theirmeaning.Waiting for a task to be completedSometimes, you need to wait for a thread to finish some operation rather thanwaiting for a particular thread to complete execution.To do this, use an event object.Event objects (TEvent) should be created with global scope so that they can act likesignals that are visible to all threads.When a thread completes an operation that other threads depend on, it callsTEvent::SetEvent.SetEvent turns on the signal, so any other thread that checks willknow that the operation has completed.To turn off the signal, use the ResetEventmethod.For example, consider a situation where you must wait for several threads tocomplete their execution rather than a single thread.Because you don t know whichthread will finish last, you can t simply use the WaitFor method of one of the threads.Instead, you can have each thread increment a counter when it is finished, and havethe last thread signal that they are all done by setting an event.The following code shows the end of the OnTerminate event handler for all of thethreads that must complete.CounterGuard is a global critical section object thatprevents multiple threads from using the counter at the same time.Counter is a globalvariable that counts the number of threads that have completed.void __fastcall TDataModule::TaskThreadTerminate(TObject *Sender){’ CounterGuard->Acquire(); // lock the counterif (--Counter == 0) // decrement the global counterEvent1->SetEvent(); // signal if this is the last threadCounterGuard->Release(); // release the lock on the counter}The main thread initializes the Counter variable, launches the task threads, and waitsfor the signal that they are all done by calling the WaitFor method.WaitFor waits for aspecified time period for the signal to be set, and returns one of the values from Table7.2.Table 7.2 WaitFor return valuesValue MeaningwrSignaled The signal of the event was set.wrTimeout The specified time elapsed without the signal being set.wrAbandoned The event object was destroyed before the timeout period elapsed.wrError An error occurred while waiting.Wr i t i ng mul t i - t hr eaded appl i c at i ons 7-9Ex e c u t i n g t h r e a d o b j e c t sThe following shows how the main thread launches the task threads and thenresumes when they have all completed:Event1->ResetEvent(); // clear the event before launching the threadsfor (i = 0; i WaitFor(20000) != wrSignaled)throw Exception;// now continue with the main thread, All task threads have finishedNote If you do not want to stop waiting for an event after a specified time period, pass theWaitFor method a parameter value of INFINITE.Be careful when using INFINITE,because your thread will hang if the anticipated signal is never received.Executing thread objectsOnce you have implemented a thread class by giving it an Execute method, you canuse it in your application to launch the code in the Execute method.To use a thread,first create an instance of the thread class.You can create a thread instance that startsrunning immediately, or you can create your thread in a suspended state so that itonly begins when you call the Resume method.To create a thread so that it starts upimmediately, set the constructor s CreateSuspended parameter to false.For example,the following line creates a thread and starts its execution:TMyThread *SecondProcess = new TMyThread(false); // create and run the threadWarning Do not create too many threads in your application.The overhead in managingmultiple threads can impact performance.The recommended limit is 16 threads perprocess on single processor systems.This limit assumes that most of those threadsare waiting for external events.If all threads are active, you will want to use fewer.You can create multiple instances of the same thread type to execute parallel code.For example, you can launch a new instance of a thread in response to some useraction, allowing each thread to perform the expected response.Overriding the default priorityWhen the amount of CPU time the thread should receive is implicit in the thread stask, its priority is set in the constructor.This is described in Initializing the threadon page 7-2
[ Pobierz całość w formacie PDF ]