我正在维护一个MFC程序,它可以通过RS232将数据从计算机A发送到计算机B.有时它会顺利传输数据,但有时会永远挂起。有两个线程按顺序将相同的数据发送到com端口。第一个线程成功发送数据,但第二个线程挂起代码“WriteFile”。当计算机A上的第二个线程挂起“WriteFile”时,我将一些无意义的数据如“1”从计算机B发送回计算机A.然后挂在计算机A上的“WriteFile”停止挂起,计算机B终于看到数据由第二个线程发送到计算机A上。
图片显示计算机A上的两个线程启动自己的测试并将消息发送回计算机B.每个线程完成自己的测试并几乎同时向计算机B发送TEST_DONE。但计算机B只看到计算机A上第一个线程发送的TEST_DONE(此时第二个线程挂在WriteFile上。)直到我从计算机B手动向计算机A发送“1”。
这是我的代码从计算机A向计算机B发送消息.cmd的长度是255。
BOOL SerialPort::AutoHandlerRES(unsigned char* cmd){
while(wait_transfer.IsLocked())
Sleep(1000);
wait_transfer.Lock();
CString out;
BOOL RetB;
UCHAR EndChar[2]={0x0D,0x0A};
out=CString(cmd);
DWORD num = out.GetLength()+2;
cmd[num-2]=EndChar[0];
cmd[num-1]=EndChar[1];
RetB=WriteFile(this->m_hCom, cmd, num, &num, NULL);
Sleep(1000);
wait_transfer.Unlock();
return RetB;}
我的问题是导致线程B挂在“WriteFile”的可能原因是什么?为什么在线程A上没有挂起?谢谢!
答案 0 :(得分:1)
来自the MSDN page about serial communications:
如果一个线程被阻塞,等待其I / O操作完成, 随后调用通信API的所有其他线程将是 阻止,直到原始操作完成。例如,如果一个 线程正在等待ReadFile函数返回,任何其他 发出WriteFile函数的线程将被阻止。
您可能会发出阻止ReadFile
完成的阻止WriteFile
。在你的情况下,它将是线程之间的竞争条件;写入通常在调用读取之前完成,但并非总是如此。
防止这种情况的最好方法是不要不小心调用ReadFile
,而是将其包装在与写入相同的锁中,并在读取之前等待接收COMM事件。原始的Win32调用是SetCommMask
和WaitCommEvent
。然后,您可以使用ClearCommError
来检测应读取的字节数(因为接收事件不会告诉您接收了多少数据)。
您还可以使用重叠IO来同时使用IO。我觉得它更干净,但并不简单。