Der Thread im Link von @hl_angel ist offenbar unvollständig.
Pollen ist in Fall einer seriellen Kommunikation schlecht, da hilft auch die Herabsetzung der Priorität nicht viel. Besser ist es, im Thread auf das Empfangen eines(mehrer) Bytes zu warten mit WaitForSingleObjekt(...).

Im folgenden Beispiel wird im Empfangsthread (ComThread) mit WaitForSingleObjekt(...) auf Ereignisse an der seriellen Schnittstelle gewartet. Auf alle muß man natürlich nicht warten, EV_RXCHAR reicht schon. Die Priorität wird hier sogar noch erhöht, um ja auch alles sofort mitzubekommen (hier wird die Zeit gemessen), ohne daß das System damit ausgebremst wird! Und wie die Datenübergabe an den ComThread funktioniert, ist auch in diesem Beispiel zu sehen.
Der Monitorthread ist nicht nowendig, die Ereignisse und Daten vom seriellen Port könne auch anderwohin gesendet werden. ABER: die Verarbeitung der Daten sollte natürlich NICHT im ComThread (oder einer von ihm aufgerufenen Funktion/Klasse) erfolgen, sondern immer gleich (in eine Message-Queue) weggeschrieben und woanders verarbeitet werden.

Code:
/************************************************************
** CommThread      : Öffnet, schließt und liest den Port,
**                   sendet die Zeiten per PostThreadMessage
**                   an den MonitorThread
************************************************************/

#include <windows.h>
#include <process.h>
#include <stdio.h>


// Prototypes:
DWORD WINAPI ComThread (LPVOID lpParam);
DWORD WINAPI MonitorThread (LPVOID lpParam);
HANDLE StartComThread (DWORD iPortNum, HWND hEdit);
long queryPrecisionTime (void);
long queryPrecisionTimeStamp (void);

// Globals:
HANDLE hCom = INVALID_HANDLE_VALUE;

// global struc contains parameter for threads
typedef struct
{
	volatile BOOL ThreadStoppen;
	volatile int iComPortNum;
	volatile DWORD  dwMonitorThreadId;
} PARAMS, *PPARAMS;

static HANDLE hEvent; 

// Message types
#define MSG_MIN_RANGE      0
// Der Message-Type für PostThreadMessage setzt sich aus
// QS_ALLPOSTMESSAGE (=256) und dem eigenem Message-Type 
// (siehe MSG_xxxxxxx) zusammen.
// Mit MSG_MIN_RANGE können verschiedene Gruppen bei 
// Bedarf gebildet werden.
#define MSG_TIME        MSG_MIN_RANGE + 1000 // vom ComThread
#define MSG_TRIG        MSG_MIN_RANGE + 2000 // reserviert
#define MSG_COMOPEN     MSG_TRIG + 4
#define MSG_COMCLOSE    MSG_TRIG + 5

#define QEVENT     "QueueEvent"


//--------------------------------------------------------------------
// COMThread
//
// erstellt eine Queue, setzt danach den Event ("Queue ist ready").
// Schließt eine geöffneten COM-Port und öffnet den neuen (Nummer ist
// in der Strukur, auf die lpParam zeigt).
// liest die queue aus.
//
// Thread Funktion
// Liest eventgesteuert den Status von CTS, DSR, ... ein und
// sendet in dwEvtMask alle zum Event gehörenden Ereignisse
// zum Monitor-Thread. 
// 
//--------------------------------------------------------------------
DWORD WINAPI ComThread (LPVOID lpParam) 
{
	long lTime;
	volatile PPARAMS pparams;                     // struct-Instanz
	pparams = (PPARAMS) lpParam;                  // Zuweisung zu lpParam
	int iPortNum = pparams->iComPortNum;          // ...
	DWORD dwMonitorThreadId = pparams->dwMonitorThreadId; // ...
	char szPort[15];
	static OVERLAPPED o;
	// Maske für SetCommMask, die bestimmt, welche Ereignisse auftreten können
	DWORD dwEvtMaskIn = EV_CTS | EV_DSR | EV_BREAK | EV_RING | EV_RXCHAR | 
											EV_RLSD | EV_ERR | EV_RXFLAG | EV_TXEMPTY;
	DWORD dwEvtMask = 0;  // Maske, in die WaitCommEvent aktuelle Werte schreibt
	BOOL bRet;

	CloseHandle (hCom);       // "alten" COM-Port schließen

	// Com Port öffnen
  wsprintf (szPort, "COM%d", iPortNum);
	hCom = CreateFile (szPort, 
		GENERIC_READ | GENERIC_WRITE,
    0,    // exclusive access 
    NULL, // no security attributes 
    OPEN_EXISTING,
    FILE_FLAG_OVERLAPPED,
    NULL);

	if (hCom == INVALID_HANDLE_VALUE)
	{
		LPVOID lpMsgBuf;
		FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | 
			FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
			NULL, GetLastError (), MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
			(LPTSTR) &lpMsgBuf, 0, NULL);
		MessageBox (NULL, (LPCTSTR)lpMsgBuf, TEXT("ComThread: error: CreateFile()"), 
			MB_OK | MB_ICONINFORMATION);
		LocalFree (lpMsgBuf);
		pparams->ThreadStoppen = TRUE;
	}
	else
	{
		if (!SetCommMask (hCom, dwEvtMaskIn)) 
			MessageBox (NULL, "SetCommMask fehlgeschlagen", "COM Port:", MB_OK | MB_ICONSTOP);

		// Create an event object for use in WaitCommEvent. 
		o.hEvent = CreateEvent (NULL,   // no security attributes 
				FALSE,  // auto reset event 
				FALSE,  // not signaled 
				NULL);  // no name 
	}

  // Setzt die Priorität "RealTime" für das Programm
  DWORD  dwProcessId;  // own process identifier
  HANDLE hProcess;                 // handle to the own process
  DWORD  dwDesiredAccess = PROCESS_SET_INFORMATION;  // access flag
  BOOL   bInheritHandle = TRUE;   // handle inheritance flag
  BOOL   bReturn;           // If the SetPriorityClass succeeds, then nonzero
  DWORD  dwPriorityClass = HIGH_PRIORITY_CLASS;

  dwProcessId = GetCurrentProcessId ();
  hProcess = OpenProcess (dwDesiredAccess, bInheritHandle, dwProcessId);
  bReturn = SetPriorityClass (hProcess, dwPriorityClass);

	printf ("\r\nComThread: %s geöffnet, warte auf Events ...", szPort);

	// eine message zum Monitor-Thread senden:
	bRet = PostThreadMessage (dwMonitorThreadId, (QS_ALLPOSTMESSAGE + MSG_COMOPEN), 
			(WPARAM)iPortNum , (LPARAM)0);

	// Auf Events warten:
	while (!pparams->ThreadStoppen) // solange weitermachen bis TRUE
	{
		WaitCommEvent (hCom, &dwEvtMask, &o);  // EventMask "scharf machen"
		// kommt der Event, ist auch die dwEvtMask geladen und es kann weitergehen
		if (WAIT_OBJECT_0 == WaitForSingleObject (o.hEvent, INFINITE)) // warten bis Event
		{
			lTime = queryPrecisionTimeStamp ();  // Zeit holen
			// Message senden. In dwEvtMask können mehrere Ereignisse gesetzt sein
			bRet = PostThreadMessage (dwMonitorThreadId, (QS_ALLPOSTMESSAGE + MSG_TIME), 
					(WPARAM)dwEvtMask , (LPARAM)lTime);
		}    // end of: if (WAIT_OBJECT_0 == ...
	}      // end of: while (...

	CloseHandle (o.hEvent);
	CloseHandle (hCom);          // COM-Port schließen

	printf ("\r\nComThread: %s geschlossen", szPort);

	bRet = PostThreadMessage (dwMonitorThreadId, (QS_ALLPOSTMESSAGE + MSG_COMCLOSE), 
			(WPARAM)iPortNum , (LPARAM)0);

	return (0);
}


//----------------------------------------------------------------------------
// MonitorThread
//
// erstellt eine Queue, setzt danach den Event und liest
// die queue aus
//----------------------------------------------------------------------------
DWORD WINAPI MonitorThread (LPVOID lpParam) 
{ 
	static char szMsg[255] = "";
	static char szMsgTmp[30] = "";
	int i = 0;
	BOOL bRet;
	MSG msg;
	volatile PPARAMS pparams;                     // struct-Instanz
	pparams = (PPARAMS) lpParam;                  // Zuweisung zu lpParam

	DWORD COMStatus;


	// create a queue for the thread
	PeekMessage ((LPMSG)&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
	// sent event after queue creation back to the threads creator
	bRet = SetEvent (hEvent);
	
	printf ("\r\nMonitorThread: warte auf Events ...");

	// get messages by message from threads local queue
	while ((bRet = GetMessage (&msg, NULL, 0, 0)) != 0)
	{
		if (bRet == -1)
		{ // handle the error and possibly exit
			MessageBox (NULL, "MonitorThread: GetMessage error", "COM Port:", MB_OK | MB_ICONSTOP);
			return NULL;  // error!
		}
		else  
		{ // a valid message is received
			switch (msg.message)
			{
			case (QS_ALLPOSTMESSAGE + MSG_COMOPEN):
				printf ("\r\nMonitorThread: MSG_COMOPEN: lParam=0x%08x wParam=0x%08x", 
					msg.lParam, msg.wParam);
				break;
				
			case (QS_ALLPOSTMESSAGE + MSG_COMCLOSE):
				printf ("\r\nMonitorThread: MSG_COMCLOSE: lParam=0x%08x wParam=0x%08x", 
					msg.lParam, msg.wParam);
				break;
				
			case (QS_ALLPOSTMESSAGE + MSG_TIME):
				// Time stamp message: lParam=time, wParam=dwEvtMask
				szMsg[0] = '\0';

				if (DWORD(msg.wParam) & EV_CTS)
				{
					GetCommModemStatus (hCom, &COMStatus);
					if (COMStatus & MS_CTS_ON)
					{ // CTS (Pin8) activated
						wsprintf (szMsgTmp, "\r\nCTS_ON : %lu µs", msg.lParam);
					}
					else
					{ // CTS (Pin8) deactivated
						wsprintf (szMsgTmp, "\r\nCTS_OFF: %lu µs", msg.lParam);
					}
					strcat (szMsg, szMsgTmp);
				}

				if (DWORD(msg.wParam) & EV_DSR)
				{
					GetCommModemStatus (hCom, &COMStatus);
					if (COMStatus & MS_DSR_ON)
					{ // DSR (Pin6) activated
						wsprintf (szMsgTmp, "\r\nDSR_ON : %lu µs", msg.lParam);
					}
					else
					{ // DSR (Pin6) deactivated
						wsprintf (szMsgTmp, "\r\nDSR_OFF: %lu µs", msg.lParam);
					}
					strcat (szMsg, szMsgTmp);
				}

				if (DWORD(msg.wParam) & EV_RLSD)
				{
					GetCommModemStatus (hCom, &COMStatus);
					if (COMStatus & MS_RLSD_ON)
					{ // DCD (Pin1) activated
						wsprintf (szMsgTmp, "\r\nRLSD_ON: %lu µs", msg.lParam);
					}
					else
					{ // DCD (Pin1) deactivated
						wsprintf (szMsgTmp, "\r\nRLSD_OFF: %lu µs ", msg.lParam);
					}
					strcat (szMsg, szMsgTmp);
				}

				if (DWORD(msg.wParam) & EV_RING)
				{
					GetCommModemStatus (hCom, &COMStatus);
					if ((COMStatus & MS_RING_ON))
					{ // RI (Pin9) activated
						wsprintf (szMsgTmp, "\r\nRING_ON: %lu µs", msg.lParam);
					}
					else
					{ // RI (Pin9) deactivated
						wsprintf (szMsgTmp, "\r\nRING_OFF: %lu µs", msg.lParam);
					}
					strcat (szMsg, szMsgTmp);
				}

				printf (szMsg);
				break;
				
			default:
				wsprintf (szMsg, "\r\nMonitorThread: default: lParam=0x%08x wParam=0x%08x message=0x%08x", 
					msg.lParam, msg.wParam, msg.message);
				MessageBox (NULL, (LPCTSTR)szMsg, "COM Port:", MB_OK | MB_ICONSTOP);
				break;
			}  // end of: switch (msg.message)
		}    // end of: if (bRet == -1) else ...
	}      // end of: while((bRet = GetMessage(...
	
	printf ("\r\nMonitorThread: beendet");
	return 0; 
} 


// Globale Variablen
// struct für Zeitmessung
union ut_LargeInteger
{
	LARGE_INTEGER o_WinPart;
	ULONGLONG       l_MyPart;
};

int i_ResetPrecisionTime = 0;
ULONGLONG l_PerfFrequ;
ut_LargeInteger uo_PerfCount;

/************************************************************************
Die Funktion queryPrecisionTimeStamp () liefert die seit dem Start des PC
verstrichene Zeit in Mikrosekunden.
************************************************************************/
long queryPrecisionTimeStamp (void)
{
	if (i_ResetPrecisionTime == 0)
	{
		i_ResetPrecisionTime = 1;
		QueryPerformanceFrequency (&uo_PerfCount.o_WinPart);
		l_PerfFrequ = uo_PerfCount.l_MyPart;
	}
	
	ut_LargeInteger uo_perfCount;
	QueryPerformanceCounter (&uo_perfCount.o_WinPart);
	return (long) (uo_perfCount.l_MyPart * 1000000 / l_PerfFrequ);
}

// *********************************************************************
int main (void)
{
	DWORD  dwMonThreadId;
	DWORD  dwComThreadId;
	HANDLE hMonThread;
	HANDLE hComThread;
	DWORD  dwState;
	PARAMS p;

	// MonitorThread erstellen:
	// Erstellt den Event für die Thread Queue
	hEvent = CreateEvent (NULL, false, true, QEVENT);
	// Thread starten und uMonThreadID für ComThread merken
	hMonThread = CreateThread (      // Handle des Threads
      NULL,                        // no security attributes 
      0,                           // use default stack size  
      MonitorThread,               // thread function 
      &p,                          // argument to thread function 
      0,                           // use default creation flags 
      &dwMonThreadId);             // returns the thread identifier 
	
	if (hMonThread == NULL) 
		printf ("\r\nCreateThread (MonitorThread) fehlgeschlagen");

	p.dwMonitorThreadId = dwMonThreadId;  // merken, für ComThread
	
	// wait for queue completition
	dwState = WaitForSingleObject (hEvent, 100);
	CloseHandle (hEvent);

	// "alten" Thread stoppen  
	p.ThreadStoppen = TRUE;
	CloseHandle (hComThread); // "alten" Thread stoppen
	p.iComPortNum = 1;
	// ComThread: Starten und Parameterstruct übergeben
	p.ThreadStoppen = FALSE;
	hComThread = CreateThread (    // Handle des Threads
    NULL,                        // no security attributes 
    0,                           // use default stack size  
    ComThread,                   // thread function 
    &p,                          // argument to thread function 
    0,                           // use default creation flags 
    &dwComThreadId);             // returns the thread identifier 

	if (hComThread == NULL) 
		printf ("\r\nCreateThread (ComThread) fehlgeschlagen");

	Sleep (30000); // nur so zum Test

	CloseHandle (hMonThread);    // MonitorThread beenden
	CloseHandle (hComThread);    // ComThread beenden

	return (0);
}
Anpassen an die Borland-Sytax/Notation sollte nicht schwer sein.

Blackbird