-
while loop w/ sleep(1) doesnt work
I am writing a software that periodically checks for CAN messages through calls to the driver libraries. And I must perform actions depending on the CAN messages I see.
At first I used a system timer and function call in response to the windows message WM_TIMER.
(i.e. SetTimer(1,10,NULL) and OnTimer() function where the processing of the messages occur.)
But that solution has proven to be too slow, and I need a faster loop. So I though to use a while loop with a sleep of 1ms so as not to lock up the cpu. However, I've read that the sleep interval can only be as low as 15ms, and anything below that will sleep for 15ms.
How can I create a faster loop without using all cpu resources?
-
Re: while loop w/ sleep(1) doesnt work
The best option would be to not poll at all, but instead be notified when an event occurs. If that isn't an option, then you have to poll.
Do you really need to poll the driver more than once every 15ms? Why?
What "driver libraries" are you referring to?
gg
-
Re: while loop w/ sleep(1) doesnt work
Quote:
Originally Posted by
acerunner316
...
How can I create a faster loop without using all cpu resources?
I don't know what you mean by "without using all cpu resources", however, you could try Multimedia Timer
-
Re: while loop w/ sleep(1) doesnt work
Quote:
Originally Posted by
Codeplug
The best option would be to not poll at all, but instead be notified when an event occurs. If that isn't an option, then you have to poll.
Do you really need to poll the driver more than once every 15ms? Why?
What "driver libraries" are you referring to?
gg
I am using Kvaser and vectorCAN, which requires polling.
And yes I do need a loop thats faster than 15ms. I am implementing a communication algorithm with handshaking. So i send a command, get its response, and send next command, get another response. All of this must occure sequentially. The response is much much faster than the polling on the PC side, so the PC side is my weakest link in the speed of this procedure. At the speed that I am polling and sending commands now, I am only using 4% of the CAN bus load, and I have plenty of space to put more messages on the bus. I just don't know how to speed it up on the PC side.
-
Re: while loop w/ sleep(1) doesnt work
Quote:
Originally Posted by
VictorN
I don't know what you mean by "without using all cpu resources", however, you could try Multimedia Timer
what I mean is that I can't use ONLY a while loop without a pause inside of it. It is my understanding that that will comsume all cpu time.
-
Re: while loop w/ sleep(1) doesnt work
So I see the Kvaser products can be used with their CANlib SDK. Is that what you're using?
Are their blocking API's you can use - instead of polling?
gg
-
Re: while loop w/ sleep(1) doesnt work
yes I am using the CANlib SDK. That is the only solution kvaser provides to communicate with their devices. I am not sure what you mean by "blocking API".
In CANlib, the function to get a message is canRead.
Code:
canStatus canRead(
int handle, long* id,
void* msg, unsigned int* dlc,
unsigned int* flag, DWORD* time);
This is the function I want to call every 1ms, which retreives messages in the device's receive buffer.
-
Re: while loop w/ sleep(1) doesnt work
The key to avoiding the "15ms" thing is to *not* make any call which would cause the OS to timeslice over to other running processes (or even check for them). In other words, you need a pause() function which remains strictly in user mode for the duration rather than entering kernel mode. Unfortunately, I'm not aware of a standard function which does this; the suggestion above to use blocking functions (possibly with timeouts if you need to detect failure) is probably the best.
EDIT: A quick Google later, I found this:
http://www.kvaser.com/index.htm
Looks like canReadWait() is what you want.
-
Re: while loop w/ sleep(1) doesnt work
Looks like canReadWait() is the blocking version. This would be much better than polling.
canReadSync() and canReadSyncSpecific() also look useful.
gg
-
Re: while loop w/ sleep(1) doesnt work
i know about the canReadWait() function for kvaser. However, my app must also work with a few other CAN adapters that are user selectable. The APIs for these other devices do not have an equivalent function, so i have to write something in my app to do it.
If by blocking function, you mean something like this:
Code:
void pauseforcount(int count)
{
int i=0;
while (i<count)
i++;
}
does the cpu freeze up during this loop?
my sequence of cmd and response can take several minutes, and I don't want the CPU to hang on my app.
-
Re: while loop w/ sleep(1) doesnt work
>> If by blocking function...
In this context, "blocking" means that the current thread is "blocked" or waiting efficiently within the OS. Meaning, the call does not return from the OS until some condition is met. For example, Sleep() is a blocking call which blocks for at least the amount of time given. If your code is spinning in a loop, that's called a "busy wait". This will count against you in the "% CPU Usage" column of task manager.
>> my sequence of cmd and response can take several minutes
Then why not just poll once a second? I see no need for polling the data any faster. And if you are willing to call Sleep(), then just call canReadWait() with a 1 second timeout. Then if data is available it will return immediately. If not, the call will block for up to 1 second.
Is this code multi-threaded? Or are you handling the UI and device interaction all within one thread?
gg
-
Re: while loop w/ sleep(1) doesnt work
Quote:
Originally Posted by
Codeplug
>> If by blocking function...
In this context, "blocking" means that the current thread is "blocked" or waiting efficiently within the OS. Meaning, the call does not return from the OS until some condition is met. For example, Sleep() is a blocking call which blocks for at least the amount of time given. If your code is spinning in a loop, that's called a "busy wait". This will count against you in the "% CPU Usage" column of task manager.
Thanks for providing the correct terminology. Yes, I want to avoid a busy wait at all costs.
Quote:
Originally Posted by
Codeplug
>> my sequence of cmd and response can take several minutes
Then why not just poll once a second? I see no need for polling the data any faster. And if you are willing to call Sleep(), then just call canReadWait() with a 1 second timeout. Then if data is available it will return immediately. If not, the call will block for up to 1 second.
what I mean is that there are so many cmd & response pairs of CAN messages that all of them in sequence can take several minutes. For example, I have 1000 cmds to send, each waiting for a response before sending the next command. Polling every 1 second will require at least 1000 seconds to complete the entire sequence of 1000 cmds. Polling every 1ms, however, dramatically reduces this time to 1 sec, which is what I'm trying to do.
Quote:
Originally Posted by
Codeplug
Is this code multi-threaded? Or are you handling the UI and device interaction all within one thread?
gg
it's single thread.
-
Re: while loop w/ sleep(1) doesnt work
Well, canReadWait() seems like exactly the right thing then. It will return immediately if a message is waiting, *or* wait up to the specified amount of time if one is not. You'd have to give us more details about these other APIs you're working with before we could get more specific.
-
Re: while loop w/ sleep(1) doesnt work
Quote:
Originally Posted by
acerunner316
Yes, I want to avoid a busy wait at all costs.
...
Polling every 1ms, however, dramatically reduces this time to 1 sec, which is what I'm trying to do.
Do you have more than one CPU/core? The strategy depends on that.
Also, the “busy wait” is only wrong if you are counting crows in your loop. If you have something like that:
Code:
while(!canRead())
;
it’s more like extreme readiness.
In any case, you should NEVER have lengthy processing on the same thread as your UI.
I would run that polling function (or the blocking canReadWait() function, if it exists) on the separate thread, and wait for it using MsgWaitForMultipleObjects() so that your UI is responsive.
Now, what do you need a sleep timer for? Even a high-precision one? That high-precision timer works pretty much like a busy loop. No better but less performing than my loop above.
If you want to achieve maximum throughput, I would suggest raising your thread’s priority.
-
Re: while loop w/ sleep(1) doesnt work
>> Polling every 1 second will require at least 1000 seconds to complete
Yes - if you only try to read something once a second. But if you use canReadWait() with a timeout, then the function will return as soon as there is data available or if a timeout occurs.
Typically, when dealing with a message-response type protocol, there is a "time window" in which a response is expected. If a response isn't received within that window, then you assume "communications error". You will have to decide at what point does a lack of a response indicate an error.
How long does it typically take to receive a response?
At what point does a lack of response indicate "communication error"?
>> it's single thread.
If you're not familiar with it, making it multi-threaded may add more complications than you care to deal with right now. But without it, you'll need to find a way to keep the UI responsive while handling CAN communications.
The single threaded approach wouldn't be too hard if, for example, you had a modal dialog with a cancel button and some sort of progress indicator. You would then use a special message loop just for this modal dialog. This special message loop would periodically pump messages while handling CAN message/response pairs.
gg
-
Re: while loop w/ sleep(1) doesnt work
I guess what I am saying is that Windows is not an RTOS #1 and #2 that not every version of Windows will provide what you need if you are using a thread. Windows XP will not be able to create a thread that reliably polls at the rate of 1ms. Windows Vista may be able to do this *more* reliably for you since it has been enchanced for multi-media purposes.
Windows XP has a 10 ms quantum.
Windiws Vista has 1 ms.
As a side note, Windows 9X and Me have 55ms quantum.
I have had speedier results with SetTimer than with threads.
There are those who believe that sleep() with a parameter of > 0 is evil.
eg: http://www.flounder.com/time.htm
-
Re: while loop w/ sleep(1) doesnt work
Quote:
Originally Posted by
acerunner316
i know about the canReadWait() function for kvaser. However, my app must also work with a few other CAN adapters that are user selectable. The APIs for these other devices do not have an equivalent function, so i have to write something in my app to do it.
I have worked with a variety of CAN bus products over the past decade, and have never seen a commercial driver/library package that did NOT support notification. A few (typically raw, older ones) required an update in order for the adapter to generate a system interrupt..
-
Re: while loop w/ sleep(1) doesnt work
Don't the other libraries have anything similar to this that you can use? http://www.kvaser.com/support/prodhe...m#using_handle
-
Re: while loop w/ sleep(1) doesnt work
Quote:
Originally Posted by
VladimirF
Also, the “busy wait” is only wrong if you are counting crows in your loop. If you have something like that:
Code:
while(!canRead())
;
not sure what you mean by "counting crow", but this is how this part of my program works
In response to user clicking start button, I do this:
while (!sequence complete)
{
//fill local buffer of CAN messages from hardware buffer using canRead()
//search buffer for reply to cmd
//if reply exist, send next cmd
//if reply doesn't exist, continue loop to read more messages
//sleep(1ms) to allow hardware buffer to fill
}
there's a lot more going on, but this is a very basic summary.
-
Re: while loop w/ sleep(1) doesnt work
Quote:
Originally Posted by
Codeplug
>> it's single thread.
If you're not familiar with it, making it multi-threaded may add more complications than you care to deal with right now. But without it, you'll need to find a way to keep the UI responsive while handling CAN communications.
The single threaded approach wouldn't be too hard if, for example, you had a modal dialog with a cancel button and some sort of progress indicator. You would then use a special message loop just for this modal dialog. This special message loop would periodically pump messages while handling CAN message/response pairs.
gg
no, i'm not familiar with multi-threading. I realize that's probably the better way to go in this situation...
Can you elaborate on the modal dialog method? thanks
-
Re: while loop w/ sleep(1) doesnt work
Quote:
Originally Posted by
ahoodin
I have had speedier results with SetTimer than with threads.
That's odd, I've tried using the SetTimer, and it is much much slower.
Btw, I'm running on a XP system.
-
Re: while loop w/ sleep(1) doesnt work
Quote:
Originally Posted by
TheCPUWizard
I have worked with a variety of CAN bus products over the past decade, and have never seen a commercial driver/library package that did NOT support notification. A few (typically raw, older ones) required an update in order for the adapter to generate a system interrupt..
I am using Kvaser, VectorCAN, and PeakCAN. If you know of such a function in those libraries, please advise. Thanks!
-
Re: while loop w/ sleep(1) doesnt work
Quote:
Originally Posted by
acerunner316
I am writing a software that periodically checks for CAN messages through calls to the driver libraries. And I must perform actions depending on the CAN messages I see.
At first I used a system timer and function call in response to the windows message WM_TIMER.
(i.e. SetTimer(1,10,NULL) and OnTimer() function where the processing of the messages occur.)
But that solution has proven to be too slow, and I need a faster loop. So I though to use a while loop with a sleep of 1ms so as not to lock up the cpu. However, I've read that the sleep interval can only be as low as 15ms, and anything below that will sleep for 15ms.
How can I create a faster loop without using all cpu resources?
long ago i had to do a similar thing and this is what i ended up doing:
Code:
HANDLE CMainFrame::m_hPortNotificationEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
// This sets up an event to notify the application if there
// are messages in the port‘s receive queue.
m_vErr = ncdSetNotification(m_vPortHandle,
(unsigned long *)&m_hPortNotificationEvent,
QUEUE_LEVEL);
if (m_vErr)
Error(m_vErr);
// then i created a thread in suspended state
// code inside the thread
DWORD WINAPI CMainFrame::ReceiveData(LPVOID pVoid)
{
DWORD dwResult = 0;
Vstatus vErr = 0;
Vevent *pEvent = NULL;
float fTimeStamp = 0;
char chTemp[100] = {0};
unsigned long ulMSGId = 0;
char chDataField[40] = {0};
CMainFrame *pThis = static_cast<CMainFrame *>(pVoid);
while(TRUE)
{
dwResult = WaitForSingleObject(m_hPortNotificationEvent, INFINITE);
switch(dwResult)
{
case WAIT_OBJECT_0:
// receive
for (;;) // read all events
{
vErr = ncdReceive1(m_vPortHandle,&pEvent);
if (vErr && vErr != VERR_QUEUE_IS_EMPTY)
{
if(pThis != NULL)
{
::MessageBox(pThis->m_hWnd, "A severe error has occured.\nHardware not present or badly installed.\nCheck (PCMCIA, Tranceiver cable, Connection to the MODAC) and try again.\nApplication will exit!",
IDS_S3,
MB_ICONERROR);
::SendMessage(pThis->m_hWnd, WM_CLOSE, 0, 0);
}
}
if (vErr == VERR_QUEUE_IS_EMPTY)
break;
if (pEvent->tag == V_RECEIVE_MSG)
{.......
if you're working with Vector's CANCard library all this should be familiar to you...
-
Re: while loop w/ sleep(1) doesnt work
Quote:
Originally Posted by
acerunner316
I am using Kvaser, VectorCAN, and PeakCAN. If you know of such a function in those libraries, please advise. Thanks!
PeakCAN (which is ancient) does not. Typically this driver is best used on a thread wtih Huerestic delays.
VectorCAN I cant find my documentation on, and most of the time I used it was with LabView (which has its own dedicated driver
Kvaser we already determined does have it....
Sounds like time for a decent class hierarchy and some background thread processing.
-
Re: while loop w/ sleep(1) doesnt work
So I found documentation for all 3:
I downloaded the "CAN Driver Library" from Vector here: https://www.vector-worldwide.com/vi_...center_en.html
It has a "VCAND.pdf" documenting their API, including the functions that Alin showed us.
I downloaded the "PCAN-PCI package" from Peak here: http://www.peak-system.com/Support.55.0.html?&L=1
It has a "PCANLight_enu.chm" that documents its API. It is indeed a bare-bones API. The MFC sample that comes with it actually polls using SetTimer().
And (again) the Kvaser API is documented online: http://www.kvaser.com/support/prodhelp/canlib38/
So I wanted to get that out there and available to readers of this thread.
Quote:
Originally Posted by
acerunner316
In response to user clicking start button, I do this:
Code:
while (!sequence complete)
{
//fill local buffer of CAN messages from hardware buffer using canRead()
//search buffer for reply to cmd
//if reply exist, send next cmd
//if reply doesn't exist, continue loop to read more messages
//sleep(1ms) to allow hardware buffer to fill
}
Getting back to your original issue - that you "need a faster loop" - Remove all calls to Sleep(). That's just wasting time. Instead, use canReadWait() with an arbitrary timeout (say 20ms) and let the loop run as fast as it wants to.
Under Vector, you can achieve the same effect of canReadWait(20ms) by setting up a notification event and calling "WaitForSingleObject(m_hPortNotificationEvent, 20)" (using Alin's code).
Under Peak, there is no "efficient waiting" for a message. My first attempt at this would be to create my own "canReadWait()" with something like this:
Code:
inline DWORD TimeElapsed(DWORD start, DWORD end)
{
if (end < start)
return (0xFFFFFFFF - start) + end;
return end - start;
}//TimeElapsed
DWORD Peak_canReadWait(TPCANMsg *MsgBuff, DWORD timeout)
{
DWORD res = CAN_Read(MsgBuff);
if (res == CAN_ERR_QRCVEMPTY)
{
DWORD start = GetTickCount();
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL);
for (;;)
{
res = CAN_Read(MsgBuff);
if (res != CAN_ERR_QRCVEMPTY)
break;
if (TimeElapsed(start, GetTickCount()) >= timeout)
break;
}//for
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
}//if
return res;
}//Peak_canReadWait
Here we are still letting the loop run as fast as it wants (no sleeps). This will show a lot of CPU utilization, but at least you'll be "playing nicer" by lowering the priority while polling.
>> Can you elaborate on the modal dialog method?
It doesn't necessarily require a modal dialog. It's just a way to allow for user input and read from the device in a single thread. In other words, it would allow you to have a "Cancel" button to allow the user to break out of the "while (!sequence complete)" loop.
gg
-
Re: while loop w/ sleep(1) doesnt work
codeplug, thanks for the details explanations and the code sample.
I've implemented the CanReadWait taht you describe above. Everything seems to work ok.
However, I have a read-only editbox that displays status and percentage of the entire procedure, and this doesn't update anymore. It goes up to about 10% and freezes. By looking at the CAN messages on a seperate software, I can see that the app is still running, only the interface seems to have frozen. If I click anything, the windows title displays the legendary "(not responding)" message until the entire process is done and I exist the while loop. Is there anyway to fix this?
Thanks
-
Re: while loop w/ sleep(1) doesnt work
Quote:
Originally Posted by
acerunner316
codeplug, thanks for the details explanations and the code sample.
I've implemented the CanReadWait taht you describe above. Everything seems to work ok.
However, I have a read-only editbox that displays status and percentage of the entire procedure, and this doesn't update anymore. It goes up to about 10% and freezes. By looking at the CAN messages on a seperate software, I can see that the app is still running, only the interface seems to have frozen. If I click anything, the windows title displays the legendary "(not responding)" message until the entire process is done and I exist the while loop. Is there anyway to fix this?
Thanks
did you at least take a look at my post? CAN messages are coming in way too fast for your interface to be responsive, so that's why you should be using a worker thread to do all the CAN processing and PostMessage to the UI when there is something you need to display.
-
Re: while loop w/ sleep(1) doesnt work
alin, yes I did read your post. thanks for that btw.
I am not familiar with multi-threading. I have only ever written simple dialog-based apps that perform a single task for each control item. Is multithreads the only way to go with what I'm trying to do here?
thanks
-
Re: while loop w/ sleep(1) doesnt work
Multithreading is hardly ever the only way, but it's often the most convenient. And with the trend towards multi-core architectures, it's just a good skill to have in any case.
-
Re: while loop w/ sleep(1) doesnt work
any recommendations on where I should start learning multi thread programming. Given that I am a self-taught programmer...well, windows programming. I learned intro C++ in school.
-
Re: while loop w/ sleep(1) doesnt work
There are a number of threading APIs, but the one I'd recommend is Boost::Thread:
http://www.boost.org/doc/libs/1_37_0...ml/thread.html
since it seems likely that the threading model in the next C++ standard will be based on this one.
The most important concept of multi-threading is, don't let multiple threads touch the same variables at the same time. Or at least not while those variables might get modified. Heavy use of stack-based locals instead of dynamic allocation or globals makes this much easier to control. For the rest, you must protect access to shared variables using mutexes or other locking mechanisms.
-
Re: while loop w/ sleep(1) doesnt work
Quote:
Originally Posted by
acerunner316
any recommendations on where I should start learning multi thread programming. Given that I am a self-taught programmer...well, windows programming. I learned intro C++ in school.
the are a number of FAQ's on CG dealing with worker threads, multithreading...feel free to give it a search.
-
Re: while loop w/ sleep(1) doesnt work
>> I have a read-only editbox that displays status and percentage of the entire procedure, and this doesn't update anymore.
If you have a GUI that needs updating, then you'll have to pump messages to keep the GUI "alive".
Code:
bool PumpMessages(bool pump_all = false)
{
MSG msg;
const size_t max_pumps = 5;
size_t num_pumps = 0;
while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
return false;
TranslateMessage(&msg);
DispatchMessage(&msg);
++num_pumps;
if (!pump_all && num_pumps == max_pumps)
break;
}//while
return true;
}//PumpMessages
You could try putting a call to PumpMessages right before the end of the for-loop in Peak_canReadWait.
Since Vector and Kvaser API's support Event signaling, you can handle CAN and Windows messages efficiently with something like this:
Code:
const DWORD timeout = INFINITE;
DWORD status;
status = MsgWaitForMultipleObjects(1, &m_hPortNotificationEvent, FALSE,
timeout, QS_ALLINPUT);
if (status == (WAIT_OBJECT_0 + 1))
{
// there are messages to process
PumpMessages(true);
}//if
else if (status == WAIT_OBJECT_0)
{
// m_hPortNotificationEvent was signaled
// if you process CAN messages until the buffer is empty, you may
// need to "sprinkle" some calls to PumpMessages() in that loop also
}//else if
else if (status == WAIT_TIMEOUT)
{
// specified timeout occurred - when not using INFINITE timeout,
// but there's not reason not to use INFINITE
}//else if
gg