http://www.thebits.org/tutorials/mjsema1.asp
Guide: Workers Threads and Signals
© Malcolm Smith, 14th October 2002
Create workers threads and wait for them to end then where you can create threads that make the application to freeze until all threads have completed their processing?
The usual scenario is that your application starts multi-thread. Before transferring to the next independent task, you need to wait for all these threads to complete. This article I will use the same thread class in front, create some instances and wait for them to end.
Below I will conduct in-depth discussions (some of the code will be omitted):
For (int i = 0; i <10; i ) {counter ; labelindex = (counter-1)% 6; TWORKERTHREAD * Thread = New Tworkerthread (True, Labalarray [labelindex], 50); thread-> freeonterminate = true; Thread-> resume ();
The same code is created 10 threads (now please ignore the facts they have the same label)
We are unable to know when all threads are all completed. This can be implemented by creating these independent threads in another thread, using a ThreadCounter who knows how much currently running threads. This is where the above thread class is called the worker thread. Below I created a master thread, create these worker threads through this thread, using the counter to determine when they are over.
Note that the initial code here will result in the deadlock mentioned earlier. The corrected version will be involved later.
This is a class definition: Class Thostthread: Public TTHREAD
{
Private:
Int counter;
Int Maxthreads;
TLABEL * Labalarray [6];
protected:
Void __fastcall execute (void);
Void __fastcall hascompleted (TOBJECT * Sender);
PUBLIC:
__fastcall thostthread (Bool CreateSuspended, TLabel * Alabelarray [6],
INT AMAXTHREADS);
}
Don't take the AMAXTHREADS parameters at this moment.
This class will create 10 threads and wait for them to complete. The implementation is as follows:
__fastcall thostthread :: Thostthread (Bool CreateSuspend (TLabel * alabel,
INT AMAXTHREADS: TTHREAD (CREATESUSPENDED), Plabel (Alabel)
{
COUNTER = 0;
Maxthreads = AMAXTHREADS;
Memcpy (Labalarray, Alabelarray, Sizeof (TLABEL *) * 6);
}
Void __fastcall thostthread :: Execute (Void)
{
Int labelindex;
// Create 10 threads, add our counter
For (int i = 0; i <10; i )
{
Counter ;
LabelIndex = (counter-1)% 6;
TWORKERTHREAD * Thread = New Tworkerthread (True, Labalarray [LabelIndex], 50);
Thread-> FreeOnterminate = true; thread-> onterminate = Hascompleted; //METHOD USED to Decrement Counter
Thread-> resume ();
}
// Waiting for all threads to end
While (! Terminated && Counter> 0)
Sleep (1);
}
Void __fastcall thostthread :: Hascompleted (TOBJECT * SENDER)
{
Counter
}
Now the code looks very good, the execute method creates 10 threads, and the counter is reduced after each thread. The Execute method returns until all threads are over. For complete, you may need to achieve this thread creation.
Thostthread * Thread = New Thostthread (True, Labalarray, 3);
Thread-> freeOnterminate = true;
Thread-> resume ();
Thread-> WaitFor ();
What happened to guess? Your application will have a difficult interrupt in the last line. Because the primary VCL thread is suspended until the master thread "thread" returns. Worker thread still tries to update the primary VCL thread (which is hang) label by synchronizing. There is also a similar problem when you don't have to synchronize but use the onterminate event. This event is called by the context of the primary VCL thread to cause the same problem. So how do you overcome this problem? Basically, you need to design your GUI (or business object), allowing it to continue to process messages, but it is known to do the appropriate operation when you create threads. Below I shows how to use TactionList in a GUI application. The button name "Run Host Thread" in the demonstration is associated with the ActionList component. When you double-click this action list component, you will see the HostthReadButton item. The only purpose I use it is to activate or disable the button mentioned above. In a large application you may have any menu items or other controls that need to be disabled when you run. Assign these controls to this action, you can activate or disable them through a line of code. (E.g:)
HostthreadButton-> enabled = false; In the above example, all controls connected to this action will be disabled. The button in the demo program is called by btnhostthread, and its Action property points to HostthreadButton. This is disabled when HostthreadButton is disabled. If you look at the BTnHostThread button on the onclick event, you will see that there is no specified event processing. Then how the code is executed when the button is pressed? I have previously declared this button's action attribute to the HostthreadButton action. You look at this action, it has an onexecute event, and this method will be called whenever you click on the button. If we have a menu item associated with this action, the menu item is selected as the same code will run. This is some code of this action on the Onexecute event (no annotations)
Thostthread * Thread = New Thostthread (True, Labalarray, 3);
Thread-> freeOnterminate = true;
Thread-> onterminate = hostthreadhascompleted;
Thread-> Resume (); hostthreadbutton-> enabled = false; At this point, we have notified the owner thread to call the hostthreadhascompleted method at the end of it. Guess what we have to do below?
Void __fastcall tform1 :: hostthreadhascompleted (TOBJECT * SENDER)
{
HostthreadButton-> enabled = true;
}
Do not have prizes. If you run this part of the demo, you will see that 6 tags are updated, buttons were initially disabled, and they were reactivated after all threads were completed. Due to the simple demonstration, you can't see 10 threads running because we only have 6 tags. Here we continue to further modify the code. Let it become this: Let 10 threads eventually run, but at the same time only 3 threads are running. Our buttons are completely completed until 10 threads can be activated. We have to add a semaphore to our owner. The signal is a synchronous object, and we use it to limit the number of created threads. This object works by handling its own counter. At any time, the value of the counter is greater than 0, allowing the thread to abort the thread when the counter is equal to 0, until a worker thread ends an counter that adds the amount of semaphore. Please do this. Add a semaphore handle to the Thostthread class, create this semaphore when constructed.
HSemaphore = CreateSemaphore (NULL, 3, 3, NULL); this creation a semaphore number of 3, maximum number of 3. Next, we modify this thread class's Execute method, as follows: (去 去 演 演 程序 中 程序)
Void __fastcall thostthread :: Execute (Void)
{
INT labelindex = 0;
For (int i = 0; i <10; i )
{
Counter ;
Labelindex = labelindex% 6;
:: WaitForsingleObject (HSemaphore, Infinite);
TWORKERTHREAD * Thread = New Tworkerthread (True, Labalarray [LabelIndex], 50);
Thread-> freeOnterminate = true;
Thread-> onterminate = hascompleted; // to reduce the method of the counter
Thread-> resume ();
Labelindex ;
}
While (! Terminated && Counter> 0)
Sleep (1);
CloseHandle (HSEMaphore);
}
Naturally, the method called at the end of each thread must also be changed.
Void __fastcall thostthread :: Hascompleted (TOBJECT * SENDER)
{
Counter
:: ReleaseSemaphore (HSemaphore, 1, NULL);
}
This code is used to guide the next item in the label array because the value of the counter is never greater than 2. Call WAITFORSINGLEOBJECT to reduce the counter processing of the semaphore. As long as this counter is greater than 0, the thread will continue. The initial loop created three workers threads, the semapcular counter is equal to 0, and then the thread is stopped in WaitforsingleObject. Any worker thread ends, the Hascompleted method is called. ReleaseSemaphore Call adds a semapcost counter again to allow the owner thread to continue. Another worker thread is created. Stop / Continue / Stop This process has been made until all 10 workers threads are created and fully executed. When the final thread ends, the Execute method completes, the GUI button is activated again. Run the demo, you will see that the first three tags are updated first, then there are three, then the front is the first, and finally the fourth (just 10 threads).
Once you understand, it's nothing.
Summary This message shows you how to create a simple thread and synchronize events with the primary VCL thread. Then we create some workers threads in a master thread, show how to avoid your app deadlock (Oh, at least makes you know typical reasons).
Finally, a method of using the number of threads in the operation of the signal is given.
Salute
Page 1 | Download source code
(Translation: 01soft)