Despite the flood of relevant answers to this question of Jason's, I decided
to take my peek at it!  It's nice to see how fast a flams burns a question!
;-)

> Originally the application sent out its message, and then sat in a
> tight loop repeatedly asking how many bytes were available and whether
> they formed a legal response yet. I can't allow Windows messages to be
> pumped from the calling code during this time because then another
> button on the UI could also try and communicate, which would be
> suicide when we're already in the middle of a message / response
> cycle. I also can't disable the interface during this call because
> these calls are going off very regularly (for example, background
> comms and foreground logging of data), and thus the UI would become
> irritating as it keeps disabling .

Suggestion (feel free to ignore, since you know more about the context of
your application):
How about not disabling the buttons, and pumping the messages, and just
alerting the user with a red sign (not a modal message box of course) that
they should wait, and clear that red sign when the comms is done?

> The problem I was hearing about (and can see for myself) is 100% CPU
> being hogged.
>
> Clearly, hammering the comms to find out when we have a message is
> inefficient and hogging the CPU. So I naively thought this was the
> problem, and hence tried to let the routines handling the comms
> provide a call that would block the main thread until SOMETHING had
> come back, to limit the number of calls to check. This code is working
> as coded, but it's not helping stop the CPU hog one little bit.
>
> A little bit of lateral investigation revealed that the CPU hog starts
> the very moment I spawn the worker thread, before I even start sending
> messages!
> This troubles me, because I really thought spawning that receive
> thread and having it wait until something happened was good karma.
>
> Here's that thread routine I spawn (for those who detest Hungarian
> notation, I apologise for your weaknesses {;v)  ):

I wonder what the "s" prefixes mean to OVERLAPPEDs?  :-)

> UINT CommsRXThreadProc(LPVOID pvParam) {
>       COMMS_RX_THREAD_DATA_S  *psThreadData ;
>       DWORD                                   dwNumBytes ;
>       OVERLAPPED                              sNotifyOverlapData ;
>
>       psThreadData = (COMMS_RX_THREAD_DATA_S *)pvParam ;
>       if (psThreadData != NULL)
>       {
>               // Set it up to notify us of incoming data.
>               ::SetCommMask(psThreadData->hPortHandle, EV_RXCHAR);
>
>               memset(&sNotifyOverlapData, 0, sizeof(OVERLAPPED) );
>               sNotifyOverlapData.hEvent = ::CreateEvent(NULL, FALSE,
FALSE, NULL);
>
>               while (!psThreadData->bTerminate)
>               {
>                       dwNumBytes = WaitForRX(*psThreadData,
sNotifyOverlapData);
>                       if (dwNumBytes > 0)
>                               ReceiveBytes(*psThreadData, dwNumBytes);
>               }
>
>               ::CloseHandle(sNotifyOverlapData.hEvent);
>
>               psThreadData->bTerminationComplete = TRUE ;
>       }
>
>       return 0 ;
> }

Apart from WaitForRX( ), looks pretty safe.

> Yes, there's a tight little loop in there also, but this is what
> WaitForRX()
> does:
>
> DWORD WaitForRX(COMMS_RX_THREAD_DATA_S& rsThreadData, OVERLAPPED&
> rsNotifyOverlapData)
> {
>       BOOL    bDone ;
>       COMSTAT sStatus ;
>       DWORD   dwEvent, dwError, dwDummy, dwNumBytes ;
>
>       dwNumBytes = 0 ;        // Until we have definitely
> been notified of something
>                                               // being received.
>
>       if (!::WaitCommEvent(rsThreadData.hPortHandle, &dwEvent,
>
> &rsNotifyOverlapData) )

(Just checking...)  Is rsThreadData.hPortHandle opened with
FILE_FLAG_OVERLAPPED?  Is the hEvent member of the OVERLAPPED object
properly created as a manual-reset event?

>       {
>               dwError = ::GetLastError();
>               if (dwError == ERROR_IO_PENDING)
>               {
>                       bDone = FALSE ;
>
>                       // Wait for completion of WaitCommEvent().
>                       while (!rsThreadData.bTerminate && !bDone)
>                       {
>                               bDone =
> ::GetOverlappedResult(rsThreadData.hPortHandle,
>
>       &rsNotifyOverlapData,
>
>       &dwDummy, FALSE);
> etc.

You're passing FALSE as the last parameter to GetOverlappedResult( ).  This
causes it to return immediately at any case, which might lead to another
roll of the loop, according to what you've tried to hide in the "etc." part!
Now that I've caught you red-handed, I guess you need to post the rest of
this function as well.  ;-)

> So I'm using official Wait...() calls to notify me when something
> happens even in the worker thread, so why is it hogging the CPU?
> Aren't these
> Wait...() calls supposed to be efficient? Or does
> WaitCommEvent() not follow the same nice notification system that
> WaitForMultipleObjects() and its companions do?

Hmm, I haven't used WaitCommEvent( ), but MSDN clearly says:

"If the overlapped operation cannot be completed immediately, the function
returns FALSE and the GetLastError function returns ERROR_IO_PENDING,
indicating that the operation is executing in the background."

Which makes me think why they've prefixed the function's name with "Wait"!
Maybe it's just been the Hungarian Notation?!  ;-)

Seriously, as it seems, the real waiting should be expected to happen in the
call to GetOverlappedResult( ).

> I feel a bit betrayed by the system {:v(

You're not the first nor the last one feeling so.

> Note that asynchronous comms is useless as I need to wait until either
> I get a valid response to what's sent, or a timeout occurs. It's a
> master / slave system (Modbus).

OK, I won't pretend I know anything about Modbus.  Did any of the above
help?

-------------
Ehsan Akhgari

Farda Technology (http://www.farda-tech.com/)

List Owner: [email protected]

[ Email: [EMAIL PROTECTED] ]
[ WWW: http://www.beginthread.com/Ehsan ]

Somewhere in the hurricane, hope is waiting.




_______________________________________________
msvc mailing list
[email protected]
See http://beginthread.com/mailman/listinfo/msvc_beginthread.com for 
subscription changes, and list archive.

Reply via email to