Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Multithread Serial Communication App using Entire CPU Time

Status
Not open for further replies.

seeplusplusnewbie

Programmer
Nov 14, 2004
9
US
I made a Multithreaded serial communication program (GUI Thread and Worker Thread) where the flow of data is continuous. Thus the way I have it is I use an Infinite loop of (Read data, do something with data and loopback to read more data in my worker thread), however this causes the cpu time to be completely used (99-100%). Now since the program is much faster then the flow of data what I want to do is: Read data, do something with it, then return to the OS then go back to the read routine and do it again so the cpu is used as minimally as possible.

How could I go about being able to recall the read function once I return to the OS without missing any data?

Does anyone have any advice or answers to my question?

Thanks
 
I've got that before but only on an XP machine where the comms port was shared between a Palmtop and my program.

You need blocking reads that will WaitForMultipleObjects or WaitForSingleObject until data is received. I found myself having to do 4 threads: one to read, one to process the reads, one to write and one for everything else.
 
Could you please elaborate on that?

I have used the WaitCommEvent() Before with the EV_CHAR event and it just didnt work with what I was doing. I made my own routine to wait until all of the byte I wanted was there and it was ok. Check below:

Code:
for( ; dwSize < 5 ; )
{
	ReadFile(hComm, &szBuf, 1, &dwIncommingReadSize, NULL);
	if(dwIncommingReadSize > 0)
	{
		dwSize += dwIncommingReadSize;
		packetbuf[x] = szBuf;
		x++;
	}
}
 
Why not just
Code:
ReadFile (hComm, packetbuf, 5, &dwIncomingReadSize, NULL);
That should block until you get 5 chars unless you've played with the CommTimeouts. I've set my timeout constant to 100 and intervalMultiplayer to 3

Also, what is your DCB.
 
After doing some tests I have concluded that it is indeed the "infinite for loop" that is causing the cpu usage to jump up completely.

So now its time to figure out how to resolve this. If i didn't mention it aready, this is what I wanted to do:

call worker thread a.k.a. Read()
read data from port
do something with data
return from read() and send control back to OS

Then go back to call worker thread a.k.a. Read() and do it all over again.

Now to me it would seem that SetTimer() would work ok, but the problem with SetTimer() is that if the called function (usually OnTimer()) doesnt finish before the SetTimer() goes off again it recalls the OnTimer() function or at least that is what I was told, maybe I am wrong.
 
I used to do it the same way as your worker thread but then it started dropping data because my "do something with data" did too much. The model I ended up with was

RawReadThread
loop
read data from port
put data in buffer

ReadThread
get data from buffer
do something with data

Where possible, keep away from the GUI timer. Have a look at CreateWaitableTimer, OpenWaitableTimer, CancelWaitableTimer and SetWaitableTimer. You can use WaitForSingleObject on that one.
 
Ideally, all 3 of the basic comm I/O tasks should be performed using overlapped I/O. this can correctly be done with either one thread (doing all comm port I/O, which i have found to work quite nicely) or with up to 3 threads (one for input, one for output, one for status changes, if important) but i found that the latter was way way overkill.

after the various I/O's are hung on the port: wait for one of them to finish, handle it as quickly as is reasonable, and then hang the next I/O to replace the one you just completed. If there is no I/O of that type pending (e.g., you've written all you have to write for now) then just don't hang any new write until you have more data. You'll always be hanging a new read, of course, unless you're shutting down the comm. (And, by "handle it", i mean put incoming data in a queue somewhere and set an event or send a message for the main program thread to pick up the data - NOT "plot the trajectory of the comet described by the incoming data")

Overlapped I/O is the preferred method of comm port I/O in Windows. The code will be somewhat verbose, but it will work perfectly, will not lose characters as long as your ports are sufficiently buffered (check the hardware buffering capabilities if you wish, and adjust the buffering if necessary and if doing so is supported by your comm port hardware), and will contain no polling at all. if you're using ANY polling in code like this, it is a clear sign of a design defect.


HOWEVER - your first statement indicates a different problem. hanging a blocking read in a loop will NOT make your program CPU-busy UNLESS your port timeouts are set incorrectly (effectively making it a nonblocking read). Set the read timeout such that it waits until one data byte is available. DO NOT set it so that it 1) returns immediately or 2) returns after a specific interval or 3) returns after x-number of bytes have been received. In this context, each of those 3 choices is incorrect. Also, hang big reads - let the port give you as much as it has in one gulp. I usually retrieve the read & write buffer size of the hardware, adjust it if it has ridiculous values, then use that as the length of my reads. (I ignore the buffer size for writes because any bytes accepted for writing will be written, barring catastrophe, or I will be notified of such by the actual write length returned when the I/O completes).
 
tmiketx:

Thank you for that very well thoughtout response to my problem. However, this problem has been solved for a while now but I forgot to update the thread.

However. I guess you could help me with another problem. Right now my Serial Library works. i can read/write correctly, However i do not think I am doing it optimally and I know that I am not doing it the overlapped way. So maybe you could help me to optimize my serial read/write function so that it is done correctly. Right now i am using a for loop to read X number of bytes from the port. Problem with this method is that it will just loop (as you'd expect) until X # of bytes are read thus it will loop forever if they are never read.

What I want to be able to do is read from the port until there is no more bytes to read. That way i dont always need to know how many bytes I need to read and the read wont block the program flow indefinitely.

Below is a sample of how i would currently read from the port:

Code:
for( Size = 0; Size < 5 ; )                                 // Loop until 5 bytes have been read
{                                                           //
	ReadFile(hComm, &Buf, 1, &IncomingReadSize, NULL);  //Read 1 byte at a time
	if(IncomingReadSize > 0)                            //If byte has been read continue
	{
		Size += IncomingReadSize;                   //Increment "bytes read" counter
		packetbuf[x] = Buf;                         //put byte read into array
		x++;                                        //increment array pointer
	}
}                                                           //else loop and try again
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top