Click to See Complete Forum and Search --> : Trouble exiting worker thread.


Daniel42
November 6th, 2004, 01:05 AM
Hi, I'm relatively new to the programming world, but decided to take on a fairly difficult challenge for someone who'd never programmed for Pocket PC and do a final year engineering assignment contain some subtantial programming.

I have run into difficulties with a worker thread. I am using it for the monitoring of a Bluetooth serial port. I am using the WaitCommEvent() function in combination with ReadFile() to read in data from the port. As I am programming for the Pocket PC platform I am unable to used overlapped files, and therefore the WaitCommEvent() function is blocking. When I want to exit the program, I believe that the thread is not being exitted due to the blocking funciton. This results in part of the process still running. The program can not be subsequently executed, and when I try to delete the executable file I get a file sharing violation error.

Could anyone please assist me in exiting the funciton?

My code for the thread, and other various functions is below. I believe the problem lies in the thread as I have eliminated the WaitCommEvent() function and the program exits successfully.

DWORD WINAPI CRealtimeTab::TheSerialThread(LPVOID lpVoid)
{
int i = 0;
int Counter = 0;
int intLength = 0;

DWORD dwCommEvent = NULL;
DWORD dwBytesRead;

char *ProcessChar = new char[1024];
char *chSerialInData = new char[1024];
char chRead;

CString CstrThreadMessage;
char *charThreadMessage;


COMMTIMEOUTS Timeout;

Timeout.ReadIntervalTimeout = 50;
Timeout.ReadTotalTimeoutConstant = 100;
Timeout.ReadTotalTimeoutMultiplier = 50;
Timeout.WriteTotalTimeoutConstant = 100;
Timeout.WriteTotalTimeoutMultiplier = 50;

CRealtimeTab *DLG;
DLG = (CRealtimeTab*)lpVoid;

GetExitCodeThread(DLG->SerialThread, &dwThreadExitCode);

SetCommTimeouts(DLG->hComPort, &Timeout);


if (!SetCommMask(DLG->hComPort, EV_RXCHAR))
// Error setting communications event mask
CstrThreadMessage.Format(_T("Error setting communications event mask"));
charThreadMessage = GetAnsiString(CstrThreadMessage, CP_ACP);
::PostMessage(DLG->m_hWnd, UWM_THREAD_MSG, (WPARAM)charThreadMessage, 0);

do
{
Counter = 0;
chSerialInData = new char[1024];

if(WaitCommEvent(DLG->hComPort, &dwCommEvent, NULL))
{
do
{
if(ReadFile(DLG->hComPort, &chRead, 1, &dwBytesRead, NULL))
{
// A byte has been read; process it.
ProcessChar[Counter] = chRead;
Counter++;
}
else
{
// An error occurred in the ReadFile call.
CstrThreadMessage.Format(_T("Read Error:\nGetLastError() returns %d"), GetLastError());
charThreadMessage = GetAnsiString(CstrThreadMessage, CP_ACP);
::PostMessage(DLG->m_hWnd, UWM_THREAD_MSG, (WPARAM)charThreadMessage, 0);
Sleep(0);
break;
}
}while(dwBytesRead);


for(i = 0; i < (Counter - 1); i++)
{
chSerialInData[i] = ProcessChar[i];
}

delete [] chSerialInData;
::PostMessage(DLG->m_hWnd, UWM_RX_SERIAL_DATA, (WPARAM)chSerialInData, (LPARAM)(Counter-1));
}
else
{
// Error in WaitCommEvent
CstrThreadMessage.Format(_T("Error in WaitCommEvent"));
charThreadMessage = GetAnsiString(CstrThreadMessage, CP_ACP);
::PostMessage(DLG->m_hWnd, UWM_THREAD_MSG, (WPARAM)charThreadMessage, 0);
break;
}
}while(WaitForSingleObject(DLG->ExitEvent, INFINITE) != WAIT_OBJECT_0);

ExitThread(dwThreadExitCode);
return 1;
}

void CRealtimeTab::OnDestroy()
{
CDialog::OnDestroy();

CloseComms();

CDialog::OnClose();

}

void CRealtimeTab::CloseComms()
{
ExitEvent = CreateEvent(NULL, FALSE, FALSE, _T("Exit"));

SetEvent(ExitEvent);

CloseHandle(SerialThread);

delete SerialThread;

ClearVariables();

m_pDevice->SPPDisconnect();
DisconnectFromStack();
m_pStack->BtRadioOff();

MessageBox(_T("Closing Comms"), NULL, MB_OK);

delete m_pDevice;
delete m_pStack;
}


Regards
Daniel.

amarcode
November 6th, 2004, 11:30 AM
You call WaitCommEvent with lpOverlapped = NULL. It is a blocking call and it means the thread function waits for an event to occur (EV_RXCHAR in your example). If there are no input bytes the WaitCommEvent does not return and your thread is frozen.
You can use the code shown below to shutdown the thread :

// thread function
DWORD WINAPI CRealtimeTab::TheSerialThread(LPVOID lpVoid)
{
// use shutdown event (m_hShutdownEvent) and WaitForSingleObject() in your thread
if(::WaitForSingleObject(m_hShutdownEvent,0)==WAIT_OBJECT_0)
{
return 0; // return from the thread
}
....
Your code
....
}
// Shutdown function
CRealtimeTab::Shutdown()
{
::SetEvent(m_hShutdownEvent); // set shutdown event
SetCommMask(m_hComPort, 0); // unblock the thread (WaitCommEvent returns immediately after this call)
if(::WaitForSingleObject(m_hYourThread,1000)!=WAIT_OBJECT_0) // m_hYourThread is a handle to the thread
::TerminateThread(m_hYourThread,1);
);
}

Daniel42
November 6th, 2004, 05:45 PM
Thanks heaps amarcode, I'll give it a try!