Multi-thread programming (16)-waitabletimer for multi-thread synchronization (waiting for timer objects) [continued 2]

Source: Internet
Author: User
Tags apc
Drinking for one day, reinstalling the system for one day, and failing to blog for two days; continue learning...

Ever wondered? Waitabletimer is in "timed wait". In the preceding example, the waitforsingleobject wait function "is also waiting", which means "Double wait". This is not good and it is a waste of resources.

In fact, as a synchronization tool, the previous methods (events, signals, and critical sections) are basically enough. waitabletimer is not used to repeat the previous functions. Its main functions are similar to the ttimer class; for example, the interval of executionCodeOr execute a piece of code at a specified time.

Now that you have a convenient ttimer, why use waitabletimer?
Because waitabletimer is more accurate than ttimer, its interval can be precise to milliseconds, its specified time, or even to 0.1 milliseconds;
The ttimer-driven wm_timer message has the lowest priority in the message queue, that is, the wm_timer message is always processed at the same time.
Another important point is that waitabletimer can be used across threads and processes.

We will continue to explore an important point: in many cases, in order to keep the thread in conflict, the thread is waiting. Since there is a waiting, what is the value of waitabletimer's very accurate timing? Our consideration of this issue can allow us to understand APC functions well.

Setwaitabletimer has a callback function (in fact, it is a process). Windows requires the following format:

 
Procedure timerapcproc (lpargtocompletionroutine: pointer; dwtimerlowvalue: DWORD; dwtimerhighvalue: DWORD); stdcall;

  

The function name contains the APC name, indicating that this is an APC function (although this name does not matter, this is the official name). What is the APC function?
APC (asyncroneus Procedure Call): asynchronous process call.

It turns out that each thread has a separate message queue and an APC Queue (the APC function waiting for execution). If the thread finds a situation in the APC queue, it will jump to the execution immediately, after the execution is completed, the system will return and process the message queue.

It is troublesome to say that you only need to pass in the function pointer in the above format. However, the callback function that can enter the APC queue is quite different from other callback functions:
After the setwaitabletimer calls the APC function in the format, you need to see a "wait" in the "current thread" before this APC function can enter the queue.
This seems confusing. For example, the APC queue has such a high priority, because the priority of resources will have a great impact on other messages, and certainly cannot be entered at will, is this like VIP seats or VIP channels in life?
That is to say, to enter the APC queue, only the call of setwaitabletimer is not enough. We also need to introduce it through the "waiting function.

Waitforsingleobject? No, it is not good enough; the following is a Windows-approved waiting function that can introduce APC columns:

 
Sleepex (); waitforsingleobjectex (); waitformultipleobjectsex (); msgwaitformultipleobjectsex (); signalobjectandwait ();

Why do I use the wait function? The preceding wait functions can also wait for the APC function to be added to the column.

The preceding several wait functions have the least sleepex parameters. Use them first:

Function sleepex (dwmilliseconds: DWORD; {millisecond count} balertable: bool {Boolean value}): DWORD; stdcall; // The first parameter is the same as the sleep parameter, it is the time when the thread waits (or is called a suspension). Once the time reaches, it will be returned regardless of the following parameters. // if the second parameter is false, sleepex will not take care of whether the APC function is included in the column; // if it is true, as long as the APC function is applied, sleepex pushes APC into the queue regardless of the first parameter and returns it along with the APC function. // Note: setwaitabletimer and sleepex must be in the same thread.

  

In this example:


Code file:
Unit unit1; interfaceuses windows, messages, sysutils, variants, classes, graphics, controls, forms, dialogs, extctrls, stdctrls; Type tform1 = Class (tform) button1: tbutton; procedure button1click (Sender: tobject); Procedure formdestroy (Sender: tobject); end; var form1: tform1; implementation {$ R *. DFM} var htimer: thandle; {APC function (process), function name and parameter name can be different, and the format must be as follows} procedure timerapcproc (lpargtocompletionroutine: pointer; dwtimerlowvalue: DWORD: DWORD); stdcall; begin form1.text: = inttostr (strtointdef (form1.text, 0) + 1); {Title + 1} end; Procedure tform1.button1click (Sender: tobject); var duetime: int64; begin htimer: = createwaitabletimer (nil, true, nil); duetime: = 0; If setwaitabletimer (htimer, duetime, 0, @ timerapcproc, nil, false) then begin sleepex (infinite, true); {infinite indicates always} end; Procedure tform1.formdestroy (Sender: tobject); begin closehandle (htimer); end.

  

Form file:

Object form1: tform1 left = 0 Top = 0 caption = 'form1' clientheight = 113 clientwidth = 203 color = clbtnface font. charset = default_charset font. color = clwindowtext font. height =-11 font. name = 'tahoma 'font. style = [] oldcreateorder = false pixelsperinch = 96 textheight = 13 object button1: tbutton left = 64 Top = 48 width = 75 Height = 25 caption = 'button1' taborder = 0 onclick = button1click endend

  

In the above example, the callback function is executed once every time the mouse clicks. As a timer, how can I get it to be executed once per second?

But every time you execute the APC function, you have to send sleepex (not to mention it) to it, so you have to call sleepex repeatedly.
How to call it? Let alone the examples that can be found on the Internet. I didn't see loop-free (too stupid), so the call in the APC function would not be finished.

Of course, we usually need to set the time interval. Next we will set the interval to 1000 (1 second ).

But then the problem arises, for example, changing the code:

VaR htimer: thandle; procedure merge (vertex: pointer; dwtimerlowvalue: DWORD; dwtimerhighvalue: DWORD); stdcall; begin form1.text: = inttostr (strtointdef (form1.text, 0) + 1 ); sleepex (infinite, true); {call sleepex} end again here; Procedure tform1.button1click (Sender: tobject); var duetime: int64; begin htimer: = createwaitabletimer (nil, true, nil); duetime: = 0; {The following parameter 1000 represents an interval of 1 second} If setwaitabletimer (htimer, duetime, 1000, @ timerapcproc, nil, false) then begin sleepex (infinite, true); end; Procedure tform1.formdestroy (Sender: tobject); begin closehandle (htimer); end;

  

The task can be completed, but the form is "dead"... what should I do? Hey, isn't multithreading learned now?

In the following example, the cancelwaitabletimer is used to cancel the timer ;:


Code file:
Unit unit1; interfaceuses windows, messages, sysutils, variants, classes, graphics, controls, forms, dialogs, extctrls, stdctrls; Type tform1 = Class (tform) button1: tbutton; button2: tbutton; Procedure button1click (Sender: tobject); Procedure button2click (Sender: tobject); Procedure destroy (Sender: tobject); end; var form1: tform1; implementation {$ R *. DFM} var htimer: thandle; {APC function} procedure merge (vertex: pointer; dwtimerlowvalue: DWORD; dwtimerhighvalue: DWORD); stdcall; begin form1.text: = inttostr (strtointdef (form1.text, 0) + 1); sleepex (infinite, true); end; {thread entry function} function mythreadfun (P: pointer): integer; stdcall; var duetime: int64; begin duetime: = 0; {setwaitabletimer must be in the same thread as sleepex} If setwaitabletimer (htimer, duetime, 1000, @ timerapcproc, nil, false) then begin sleepex (infinite, true); end; result: = 0; end; Procedure tform1.button1click (Sender: tobject); var ID: DWORD; begin {create waitabletimer object} If htimer = 0 then htimer: = createwaitabletimer (nil, true, true, nil); createthread (nil, 0, @ mythreadfun, nil, 0, ID); {create thread} end; Procedure tform1.button2click (Sender: tobject); begin cancelwaitabletimer (htimer ); {cancel timer} end; Procedure tform1.formdestroy (Sender: tobject); begin closehandle (htimer); end.
 
   
 

Form file:

 
Object form1: tform1 left = 0 Top = 0 caption = 'form1' clientheight = 113 clientwidth = 203 color = clbtnface font. charset = default_charset font. color = clwindowtext font. height =-11 font. name = 'tahoma 'font. style = [] oldcreateorder = false pixelsperinch = 96 textheight = 13 object button1: tbutton left = 55 top = 32 width = 97 Height = 25 caption = #21551 #21160 #23450 #26102 #22120 taborder = 0 onclick = button1click end object button2: tbutton left = 55 top = 63 width = 97 Height = 25 caption = #21462 #28040 #23450 #26102 #22120 taborder = 1 onclick = button2click endend

  

Using the APC callback function is the right path for waitabletimer. How can we pass parameters to this function next time.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.