COM端口读取 - 超时发生后线程保持活动状态

时间:2010-12-29 19:43:19

标签: c++ c serial-port

我有一个dll,它包含一个名为ReadPort的函数,它从串行COM端口读取数据,用c / c ++编写。使用_beginthreadex从另一个WINAPI函数的额外线程中调用此函数。当COM端口有要读取的数据时,工作线程返回数据,正常结束,调用线程关闭工作者的线程句柄,并且dll工作正常。

但是,如果在COM端口上调用ReadPort而没有挂起数据,则在发生超时时WaitForSingleObject返回WAIT_TIMEOUT但工作线程永远不会结束。结果,虚拟内存每次增长大约1 MB,物理内存增长一些KB,调用dll的应用程序变得不稳定。我也尝试使用TerminateThread(),但我得到了相同的结果。

我必须承认,虽然我有足够的开发经验,但我不熟悉c / c ++。在发布之前我做了很多研究,但不幸的是我无法解决我的问题。

有没有人知道如何解决这个问题?但是,我真的想坚持这种解决方案。另外,我想提一下,我认为我不能使用任何全局变量来使用某种额外事件,因为每个COM端口可能会多次调用每个dll的函数。

我在下面发布了我的代码的一些部分:

工人主题:

unsigned int __stdcall ReadPort(void* readstr){

DWORD  dwError; int   rres;DWORD  dwCommModemStatus, dwBytesTransferred;
int ret;
char szBuff[64] = "";

ReadParams* params = (ReadParams*)readstr;

ret = SetCommMask(params->param2, EV_RXCHAR | EV_CTS | EV_DSR | EV_RLSD | EV_RING);
if (ret == 0)
{
    _endthreadex(0);
    return -1;
}
ret = WaitCommEvent(params->param2, &dwCommModemStatus, 0);
if (ret == 0)
{
    _endthreadex(0);
    return -2;
}
ret = SetCommMask(params->param2, EV_RXCHAR | EV_CTS | EV_DSR | EV_RLSD| EV_RING);
if (ret == 0)
{
    _endthreadex(0);
    return -3;
}

if (dwCommModemStatus & EV_RXCHAR||dwCommModemStatus & EV_RLSD)
{
    rres = ReadFile(params->param2, szBuff, 64, &dwBytesTransferred,NULL);
    if (rres == 0)
    {
        switch (dwError = GetLastError())
        {
            case ERROR_HANDLE_EOF:
            _endthreadex(0);
            return -4;
        }

        _endthreadex(0);
        return -5;
    }
    else
    {
        strcpy(params->param1,szBuff);
        _endthreadex(0);
        return 0;
    }
}
else
{
    _endthreadex(0);
    return 0;
}
_endthreadex(0);
return 0;}

致电主题:

int WINAPI StartReadThread(HANDLE porthandle, HWND windowhandle){

HANDLE hThread;
unsigned threadID;
ReadParams readstr;
DWORD ret, ret2;

readstr.param2 = porthandle;

hThread = (HANDLE)_beginthreadex( NULL, 0, ReadPort, &readstr, 0, &threadID );
ret = WaitForSingleObject(hThread, 500);

if (ret == WAIT_OBJECT_0)
{
    CloseHandle(hThread);  
    if (readstr.param1 != NULL)
        // Send message to GUI
    return 0;
}
else if (ret == WAIT_TIMEOUT)
{
    ret2 = CloseHandle(hThread);
    return -1;
}
else
{
    ret2 = CloseHandle(hThread);
    if (ret2 == 0)
    return -2;
}}

提前谢谢你,

SNA。

3 个答案:

答案 0 :(得分:1)

WaitForSingleObject通话中的延迟更改为5000或10000,我打赌您的问题频率会下降。

埃德温的回答也是有效的。由于您关闭了线程句柄,因此生成的线程不会死亡。

在您超时时,无法保证ReadPort线程已经开始。 Windows需要很长时间才能启动一个帖子。

以下是一些建议:

  • 您永远不会检查beginthreadex的返回值。你怎么知道线程开始了?

  • 使用您熟悉的同步方法将ReadPort线程启动与StartReadThread同步。它可以像整数标志一样简单,ReadPort在准备工作时设置为1。然后主线程可以在该点开始其真正的等待。否则你永远不会知道使用调试器在2个线程之间发生了什么。在您的同步方法表明WaitForSingleObject正在运行之前,请不要在StartReadThread中拨打ReadPort的时间超时。

  • 您不应使用strcpy复制从ReadFile串行端口收到的字节。 ReadFile告诉你它读取了多少字节。使用该值并memcpy填充缓冲区。

  • 查看herehere,了解如何将ReadFile超时,以便您的阅读不是无限期的。在Windows上永远阻止是一种灾难,因为它可能导致你无法杀死的僵尸进程,以及其他问题。

  • 您没有向StartReadThread传达有关ReadPort主题中发生的事情的状态。你怎么知道ReadPort中放置了多少字节szBuff?要获取theads退出代码,请使用GetExitCodeThread。记录here。请注意,如果您关闭了线程句柄,则无法使用GetExitCodeThread

答案 1 :(得分:1)

请勿使用WaitCommEvent。即使没有数据等待,您也可以呼叫ReadFile

使用SetCommTimeouts使ReadFile本身超时,而不是在线程间通信上建立超时。

答案 2 :(得分:0)

在超时后的调用线程中,关闭线程句柄。这只会阻止您使用手柄。然而,工作线程仍在运行。你应该使用一个等待的循环。