使用 WaitCommEvent 时 WriteFile 挂起应用程序

Som*_*uts 5 c winapi serial-port writefile readfile

我遇到了使用事件驱动方法进行串行端口通信的 win32 编程问题。我将我的通信句柄创建为:

hComm = CreateFile(lpszCommName, GENERIC_READ | GENERIC_WRITE, 0,
    NULL, OPEN_EXISTING, 0, NULL);
Run Code Online (Sandbox Code Playgroud)

我将 CommTimeouts 设置为:

    commTimeout.ReadIntervalTimeout = MAXWORD;
    commTimeout.ReadTotalTimeoutConstant = 0;
    commTimeout.ReadTotalTimeoutMultiplier = 0;
    commTimeout.WriteTotalTimeoutConstant = 0;
    commTimeout.WriteTotalTimeoutMultiplier = 0;
Run Code Online (Sandbox Code Playgroud)

我为 ReadFile 创建了一个线程,如下所示:

SetCommMask(hComm, EV_RXCHAR);
while (isConnected)
{
    if (WaitCommEvent(hComm, &dwEvent, NULL)) //If i comment out this block my write file will work fine
    {
        ClearCommError(hComm, &dwError, &cs);
        if ((dwEvent & EV_RXCHAR) && cs.cbInQue)
        {
            if (!ReadFile(hComm, str, cs.cbInQue, &read_byte, NULL))
              /* Process error*/
            else if (read_byte)
                /* Print to screen */
        }
        else {
            /* Process error*/
        }
    }
}
PurgeComm(hComm, PURGE_RXCLEAR);
Run Code Online (Sandbox Code Playgroud)

我的 Wrifile 进入 WndProc,当 WM_CHAR 被触发时,WndProc 将字符发送到通信设备:

    VOID Write_To_Serial(WPARAM wParam, HWND hwnd){
        DWORD write_byte;
        char    str[10];
        sprintf_s(str, "%c", (char)wParam);         //Convert wParam to a string
        WriteFile(hComm, str, strlen(str), &write_byte, NULL)//Program hangs here
    }   
Run Code Online (Sandbox Code Playgroud)

我的问题是每次调用 WriteFile() 时我的应用程序都会挂起,我必须强制关闭它。如果我在我的阅读线程中注释掉 WaitCommEvent() 它工作正常,但我无法阅读。任何指针将不胜感激。谢谢

小智 2

这是同步 IO 操作的预期行为。

根据 MSDN 串行通信文章 ( https://msdn.microsoft.com/en-us/library/ff802693.aspx ) 中的以下描述,

应用程序有责任正确序列化对端口的访问。如果一个线程因等待其 I/O 操作完成而被阻塞,则随后调用通信 API 的所有其他线程都将被阻塞,直到原始操作完成。例如,如果一个线程正在等待 ReadFile 函数返回,则发出 WriteFile 函数的任何其他线程都将被阻塞。

WriteFile 必须等待 WaitCommEvent 函数完成其操作。

一个小的解决方法是在需要调用 WriteFile 时取消挂起的 WaitCommEvent 操作(例如通过使用 CancelIoEx API)。

 VOID Write_To_Serial(WPARAM wParam, HWND hwnd){
        DWORD write_byte;
        char    str[10];
        sprintf_s(str, "%c", (char)wParam);         //Convert wParam to a string
        CancelIoEx(hComm, NULL);
        WriteFile(hComm, str, strlen(str), &write_byte, NULL);//Program hangs here
    }  
Run Code Online (Sandbox Code Playgroud)

取消时 WaitCommEvent 返回 FALSE。因此,WaitCommEvent 之后的代码将不会被执行。

然而,在极端情况下,调用 ReadFile 函数的线程有可能在 WndProc 到达 WriteFile 之前重新调用 WaitCommEvent 函数。如果出现这种情况,需要单独处理。也许当 WaitCommEvent 返回 FALSE 时稍微延迟一下就可以了。