PDA

Click to See Complete Forum and Search --> : VB6 - A very precise timer using Multithreading


CVMichael
Mar 5th, 2008, 12:34 AM
This is a perfect example on how to use Multithreading in VB6

In the zip attached there are several projects, one of them is a Timer thread with 1 millisecond precision (at least).

Here is an explanation on what each project does:
QPTimerThread - Is the main Timer Thread
QPTimerTestSingleThread - Is a simple example on how to use the timer by showing an Analog clock with a line for Milliseconds also
QPTimerControl - Is a user control that encapsulates the Timer Thread so that you can create multiple timers at run time using control arrays.
QPTimerTestMultiThread - Is an example on how to use the control, the application will load as many timers as it can fit on the screen horizontally, and displays the events as changes in color in pictureboxes.

If you want to test with more than one thread compile the QPTimerThread project, and make sure that all the projects are referencing the QPTimer.exe

The Timer Thread will accept an Interval of 0.0001 Milliseconds increments (because it's using Currency variable type), but the actual precision varies between 0.1 ms to 1 ms. Also, the smallest Interval accepted by the Timer Thread is 0.5 milliseconds. I did that because it is an approximate average of it's precision, and also because at 0.5 milliseconds it means that it will fire 2000 times per second, and that is quite a lot for a VB application.

Each Timer Thread from the moment it starts it goes in an Infinite loop, and there are 2 ways to stop it. First is through the TimerEvent() by passing False to the ContinueTimer parameter, this means that the application using the timer has to keep passing "True" to the timer to "keep it alive". The ContinueTimer is fine to use if your intervals are small, but if you use high intervals, you won't be able to stop the timer this way, that is why I've added a second option to stop the timer. And that is to send a Windows message to the timer thread telling it to exit the infinite loop, and that is done by simply running this line of code:

PostMessage mTimerWindow_hWnd, WM_USER + 1, 123456789, 987654321

I picked the 123456789 and 987654321 values to pass through the parameters to make sure that no other application will stop the timer unintentionally.

The precision of the timer comes from QueryPerformanceCounter API, and it's using the Sleep API to pause the thread for ~1 ms at the time so that it does not take a lot of resources (CPU) from the computer.

The TimerEvent() returns 2 parameters that might be of interest to you:
PrevEventDuration - is the duration of how much time was spent in the previous call to TimerEvent, in other words, how much time your code took to run in the previous event.
RunningInterval - if your code in the event runs longer than the Interval you set it to run, the RunningInterval will accumulate the time it is behind, and when your code runs faster than the Interval, the RunningInterval will get shorter up to 0 (zero) meaning it is not behind.

When you call the "StartTimer" function you pass the Mode to run in.
Mode1 means that if the timer runs behind, it will recover when it has the chance.
Mode2 means that if the timer runs behind, and it is more than TimeEventDrop value, then it will drop the event and seek to next event without calling the TimerEvent()
for example, if you call it like this "MyTimer.StartTimer 100, Mode2, , 50" and your code in the TimerEvent() takes 151 ms, then next event will be after 200 ms after the previous TimerEvent() call.
Mode3 is the same as the regular VB6 timer, except it is more precise. The interval is counted from the moment the TimerEvent() ends to the time it starts again. So if the interval is 100 ms, and your code runs for 20 ms, then the next TimerEvent() call is after 120 ms.

There are quite a lot more things that have to be explained, but the post will be too long, and I don't want to bore anyone... If you want to further understand how it works, please look at the code first, then ask questions if you have any.

If you have any questions or if you have any problem with any of the code, please post here.

Also... if you are a complete noob to VB and Multithreading, please post in the General VB forum (http://www.vbforums.com/forumdisplay.php?f=1), the code in this post is for moderate skill level programmers and up...

Screen shots:

QPTimerTestSingleThread - Single Thread app:
62659

QPTimerTestMultiThread - Multi Thread app:
62660

Eranga Pilimatalawwe
Apr 16th, 2008, 09:55 AM
Can Some One Please Send Me A Working Copy Of The Timer? My Email Is brainiacguy@hotmail.com

CVMichael
Apr 16th, 2008, 10:04 AM
OK... what do you mean by a "Working Copy" ?

You cannot get it to work ?

And we don't send stuff through e-mail, everything get's posted on the forums...

And you should remove your e-mail from the post if you don't want to get a lot of spam from the bots

Senacharim
Apr 17th, 2008, 01:23 AM
Can Some One Please Send Me A Working Copy Of The Timer? My Email Is brainiacguy@hotmail.com

Was the link to the zip file too complicated for you??

CVMichael
Apr 17th, 2008, 07:35 AM
I think he is expecting a reply through e-mail, but that will never happen from me....

NanniEvs
May 8th, 2008, 05:37 AM
Hi CVMichael and hi to all.

Sorry for English.

I am very interested to your code, because I have need to implement
a not Blocking Timer in my application.

My application use a timer for display countdown duration of video file
in a label and it fired every 40ms for counting frame.
My problem is that the Timer stop to count frame when other activity
are performed(e.g. switching file,load playlist…).

Can I use your code for this?
How I can implement a timer class with event and running in separate thread?
Can you show me some example?

I’m not expert with MultiThread application.

Thanks for your time
Best Regards
Nanni

CVMichael
May 8th, 2008, 08:09 AM
The timer is in it's own thread, but your application (the code and interface/form) is only one thread.

Because your application is only in one thread, and your code is processing, the application interface (the form) will get "stuck" and it wont refresh the form until the code is done, you probably saw this many times...

Also, what this means is that if your application is busy doing something, and the timer fires, your application will not be able to process the timer event until it's done doing whatever it was doing, and there is nothing you can do about that (without changing the code), because events don't interrupt the code.

There are 2 things you can do that will let the timer fire:

1) Use DoEvents in every sub/function that does a lot of processing, inside loops especially... but this will slow down the functions. So you have to be carefull where you put the DoEvents, because if DoEvents is called too often then your functions will be really slow, and if it's not called enough times, then the timer/interface will still get stuck once in a while.

2) Put the code that takes a lot of processing (like loading the files, load playlist, etc.) in it's own thread.
That way, the loading file code will not interfere with the form/interface thread, and it will not interfere with the other threads like the timer.

So in other words, to be more specific about your question:
There is nothing you can do to make the timer fire right away if the code in your application/interface does not allow it to fire...

You have to change your existing code to allow the timer to fire.

Here is visual representation of what I mean:
http://www.vbforums.com/attachment.php?attachmentid=64007&stc=1&d=1210252033
Right now, you have the "Load file" and "Load playlist" in the same thread as the interface, what you have to do is take all that code out, and put it in it's own thread so that the interface can do everything related to the interface only...

NanniEvs
May 8th, 2008, 01:01 PM
Hi Michael
thanks for your reply.

Your explanations have been very useful :)

The only problem is that I don't know how to start.
How implement MultiThread in Vb?
Do you have some suggestion?

Thanks for your time
Best Regards
Nanni

CVMichael
May 8th, 2008, 02:52 PM
Take a look at the attached projects

I made a sample thread for you, and I made it as simple as possible, you can't do it more simple than that....

Make sure you run the thread first (or compile it), and make sure that the ThreadTest project still has the propper reference, if not, just add the reference to the ThreadTemplate

coolcurrent4u
Jul 12th, 2008, 11:31 PM
how do i add the reference to the ThreadTemplate?

CVMichael
Jul 13th, 2008, 10:59 PM
There are 2 ways...

You compile the thread, then open your project and go to "Project" menu, and click on "References", in the list, you should see "ThreadTemplate", and if you don't, click on browse, and find the thread exe, and select it.

Another way, is to just run the thread, then in another VB instance, open your project, and go to "project" menu, then click on "References", and you should see it in the list.

akhileshbc
Mar 2nd, 2010, 10:34 AM
Thanks CVMichael ...:wave: