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
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