Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WriteFile hangs the application when using WaitCommEvent

I am encoutering a issues with win32 programming doing a serial port communication using a event-driven approach. I have my communication handle created as:

hComm = CreateFile(lpszCommName, GENERIC_READ | GENERIC_WRITE, 0,
    NULL, OPEN_EXISTING, 0, NULL);

and i set my CommTimeouts as:

    commTimeout.ReadIntervalTimeout = MAXWORD;
    commTimeout.ReadTotalTimeoutConstant = 0;
    commTimeout.ReadTotalTimeoutMultiplier = 0;
    commTimeout.WriteTotalTimeoutConstant = 0;
    commTimeout.WriteTotalTimeoutMultiplier = 0;

I created a thread for ReadFile which looks like this:

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);

My Wrifile goes into WndProc which sends characters to the communication device when WM_CHAR is triggered:

    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
    }   

My problem is everytime WriteFile() is called my application hangs and I have to force to close it. And if I comment out the WaitCommEvent() in my read thread it works fine, but I can't read then.Any pointers would be appreciated. thanks

like image 896
Some_Tasty_Donuts Avatar asked Nov 10 '22 03:11

Some_Tasty_Donuts


1 Answers

This is the expected behavior of Synchronous IO operations.

As per the following description in Serial Communications article in MSDN (https://msdn.microsoft.com/en-us/library/ff802693.aspx),

It is the responsibility of the application to serialize access to the port correctly. If one thread is blocked waiting for its I/O operation to complete, all other threads that subsequently call a communications API will be blocked until the original operation completes. For instance, if one thread were waiting for a ReadFile function to return, any other thread that issued a WriteFile function would be blocked.

WriteFile has to wait until WaitCommEvent function has completed its operation.

A small workaround would be to cancel the pending WaitCommEvent operation (for instance by using CancelIoEx API) when WriteFile needs to be invoked.

 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
    }  

WaitCommEvent returns FALSE when canceled. Hence,the code following WaitCommEvent will not be executed.

However, in extreme case, there is a chance, where the thread invoking the ReadFile function, re invokes the WaitCommEvent function, before WndProc gets to WriteFile. If this occurs, it needs to be handled separately. Maybe a small delay when WaitCommEvent returns FALSE would do.

like image 89
Duleeka Gunatilake Avatar answered Nov 14 '22 23:11

Duleeka Gunatilake