我有一个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。
答案 0 :(得分:1)
将WaitForSingleObject
通话中的延迟更改为5000或10000,我打赌您的问题频率会下降。
埃德温的回答也是有效的。由于您关闭了线程句柄,因此生成的线程不会死亡。
在您超时时,无法保证ReadPort
线程已经开始。 Windows需要很长时间才能启动一个帖子。
以下是一些建议:
您永远不会检查beginthreadex
的返回值。你怎么知道线程开始了?
使用您熟悉的同步方法将ReadPort
线程启动与StartReadThread
同步。它可以像整数标志一样简单,ReadPort
在准备工作时设置为1。然后主线程可以在该点开始其真正的等待。否则你永远不会知道使用调试器在2个线程之间发生了什么。在您的同步方法表明WaitForSingleObject
正在运行之前,请不要在StartReadThread
中拨打ReadPort
的时间超时。
您不应使用strcpy
复制从ReadFile
串行端口收到的字节。 ReadFile
告诉你它读取了多少字节。使用该值并memcpy
填充缓冲区。
查看here和here,了解如何将ReadFile
超时,以便您的阅读不是无限期的。在Windows上永远阻止是一种灾难,因为它可能导致你无法杀死的僵尸进程,以及其他问题。
您没有向StartReadThread
传达有关ReadPort
主题中发生的事情的状态。你怎么知道ReadPort
中放置了多少字节szBuff
?要获取theads退出代码,请使用GetExitCodeThread
。记录here。请注意,如果您关闭了线程句柄,则无法使用GetExitCodeThread
。
答案 1 :(得分:1)
请勿使用WaitCommEvent
。即使没有数据等待,您也可以呼叫ReadFile
。
使用SetCommTimeouts
使ReadFile
本身超时,而不是在线程间通信上建立超时。
答案 2 :(得分:0)
在超时后的调用线程中,关闭线程句柄。这只会阻止您使用手柄。然而,工作线程仍在运行。你应该使用一个等待的循环。