在Remon Spekreijse 写的CserialPort类中,串口监视线程相关代码如下文,调用CSerialPort::ClosePort有时候不能监视关闭线程。
用AfxBeginThread创建的线程除了调用AfxEndThread还可以用什么函数关闭?
BOOL CSerialPort::StartMonitoring()
{
if (!(m_Thread = AfxBeginThread(CommThread, this)))
return FALSE;
TRACE("Thread started\n");
return TRUE;
}
BOOL CSerialPort::ClosePort()
{

// if the thread is alive: Kill
do
{
SetEvent(m_hShutdownEvent);
} while (m_bThreadAlive);
// if port is open , close it
if (m_hComm != NULL)
{
CloseHandle(m_hComm);
m_hComm = NULL;
}
return 1;
}UINT CSerialPort::CommThread(LPVOID pParam)
{
// Cast the void pointer passed to the thread back to
// a pointer of CSerialPort class
CSerialPort *port = (CSerialPort*)pParam;

// Set the status variable in the dialog class to
// TRUE to indicate the thread is running.
port->m_bThreadAlive = TRUE;

// Misc. variables
DWORD BytesTransfered = 0; 
DWORD Event = 0;
DWORD CommEvent = 0;
DWORD dwError = 0;
COMSTAT comstat;
BOOL  bResult = TRUE;

// Clear comm buffers at startup
if (port->m_hComm) // check if the port is opened
PurgeComm(port->m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT); // begin forever loop.  This loop will run as long as the thread is alive.
for (;;) 
{  bResult = WaitCommEvent(port->m_hComm, &Event, &port->m_ov); if (!bResult)  

// If WaitCommEvent() returns FALSE, process the last error to determin
// the reason..
switch (dwError = GetLastError()) 

case ERROR_IO_PENDING: 

// This is a normal return value if there are no bytes
// to read at the port.
// Do nothing and continue
break;
}
case 87:
{
// Under Windows NT, this value is returned for some reason.
// I have not investigated why, but it is also a valid reply
// Also do nothing and continue.
break;
}
default:
{
// All other error codes indicate a serious error has
// occured.  Process this error.
port->ProcessErrorMessage("WaitCommEvent()");
break;
}
}
}
else
{
// If WaitCommEvent() returns TRUE, check to be sure there are
// actually bytes in the buffer to read.  

bResult = ClearCommError(port->m_hComm, &dwError, &comstat); if (comstat.cbInQue == 0)
continue;
} // end if bResult // Main wait function.  This function will normally block the thread
// until one of nine events occur that require action.
Event = WaitForMultipleObjects(3, port->m_hEventArray, FALSE, INFINITE); switch (Event)
{
case 0:
{
// Shutdown event.  This is event zero so it will be
// the higest priority and be serviced first.
  port->m_bThreadAlive = FALSE;
// Kill this thread.  break is not needed, but makes me feel better.
AfxEndThread(100);
break;
}
case 1: // read event
{
GetCommMask(port->m_hComm, &CommEvent);
if (CommEvent & EV_CTS)
::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_CTS_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr);
if (CommEvent & EV_RXFLAG)
::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_RXFLAG_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr);
if (CommEvent & EV_BREAK)
::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_BREAK_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr);
if (CommEvent & EV_ERR)
::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_ERR_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr);
if (CommEvent & EV_RING)
::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_RING_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr);

if (CommEvent & EV_RXCHAR)
// Receive character event from port.
ReceiveChar(port, comstat);

break;
}  
case 2: // write event
{
// Write character event from port
WriteChar(port);
break;
} } // end switch } // close forever loop return 0;
}

解决方案 »

  1.   

    线程执行体函数返回,线程自动停止,调用CloseHandle(threadid)关闭内核对象即可
      

  2.   

    1、可以让你的线程函数正常返回(return 0)
    2、TerminateThread可以强制关闭线程,一般不建议使用这个函数,容易造成线程所用的资源无法释放,关闭之后要调用CloseHandle()函数来关闭线程句柄
      

  3.   

    我用SetEvent(m_hShutdownEvent)也不能正常返回,不知道哪里出错了
    要么只能用TerminateThread了,虽然危险一点
      

  4.   

    由于AfxEndThread内部由C库函数实现,故可以用C库函数的结束线程的函数,但建议不要混用三套线程函数.
      

  5.   

    1.設個Event
    2.在入線程前Reset
    3.在線程內做判斷,若Event被Set即return
    4.在你想關閉線程時Set這個Event
      

  6.   

    可以从外部用事件通知来优雅的结束线程
    m_pThreadWrite=AfxBeginThread(ThreadProc,(LPVOID)this);UINT CMyClass::ThreadProc(LPVOID lp)
    {
    CMicrophoneInput* pInput=(CMicrophoneInput*)lp;
    return pInput->Run();
    }
    UINT CMyClass::Run()
    {
    HRESULT hr;
    if(!InitInstance()){
    TRACE("InitInstance failed\r\n";
    return ExitInstance();
    }
    while(!IsKilling()){
    //do something
    }
    return ExitInstance();
    }
    BOOL CMyClass::InitInstance()
    {
    m_eventKill.ResetEvent();
    m_eventDead.ResetEvent();
    //do something
    return TRUE
    }
    UINT CMyClass::ExitInstance()
    {
    //do something
    m_eventDead.SetEvent();
    return 0;
    }BOOL CMyClass::IsDead()
    {
    return WaitForSingleObject(m_eventDead,0)==WAIT_OBJECT_0;
    }
    BOOL CMyClass::IsKilling()
    {
    return WaitForSingleObject(m_eventKill,0)==WAIT_OBJECT_0;
    }
    在外部可以这样终止线程
    //check if dead
    if(!IsDead()&&m_pThreadWrite!=NULL){
    m_eventKill.SetEvent();
    WaitForSingleObject(m_eventDead,INFINITE);
    m_pThreadWrite=NULL;
    }
      

  7.   

    TerminateThread最简单,不过不推荐
    还是在结构里找原因