看似stdout上的WriteFile死锁

时间:2018-02-06 15:38:07

标签: c++ multithreading

我正在编写一个小应用程序,它通过串口处理预定义的消息交换(基本上是一个自定义应用程序级协议)。 它的主要部分是一个状态机,它定义了对某个预期消息的响应,停止条件,预期消息的超时等,以及一个单独监听(通过阻塞调用)的“事件循环”线程到通信事件,当它被唤醒时,它将它传递给要处理的状态机。这反过来将使状态流动并重复该过程,直到达到最终状态,此时主线程被唤醒(正在等待std :: cond_var)并加入线程。

出现问题时,出乎意料的是,对运营商的呼叫<< cout无限期地阻塞事件循环线程。调用堆栈显示线程正在WriteFile调用中等待。这似乎是一个僵局。我没有关于Windows API和内部工作的文档,但它似乎显然不会给用户带来任何潜在的同步问题(死锁),即使它可能无法按预期工作(我明白不排除访问权限)例如stdout的那个部分至少会导致交错消息 - 这不是我的问题。)

我附加了2个printcreens,其中我捕获了Visual Studio显示的线程堆栈。我真的相信应该没有应用程序编写用户空间,无论多么糟糕,都会导致控制台输出死锁,这就是为什么我不在这里粘贴代码。

搜索网络一天半,此时我不知道如何重新搜索谷歌搜索以获取一些有用的信息。即使我确实得到了,也不要认为我必须知道。你能指点我一些方向吗?也许是stdout的常见问题。或者在我的代码中我可以做的非常糟糕的事情导致这种死锁。提前谢谢。

First operator<< sometimes reproduces the issue

At this point is usually the problem seen. A communication event just came in after a long delay/it timed out

void CSerialConnection::funct(std::tuple<bool, bool, int> args)
{


    bool singleByteExpected = get<1>(args), stopped = get<0>(args);
    unsigned int timeoutValue = get<2>(args);
    bool terminate = false;

    DWORD modemStatus;
    OVERLAPPED osStatus;

    memset(&osStatus, 0, sizeof(OVERLAPPED));
    osStatus.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

    cout << "Starting communication event loop ... " << endl;

    BOOL fWaitingOnStat = FALSE;
    BOOL bReadStatus = FALSE;

    do
    {
        if (!fWaitingOnStat)
        {
            cout << "Listening for " << (singleByteExpected ? "control character .. " : "command payload .. ") << endl;
            SetCommMask(mHandle, (singleByteExpected ? EV_RXCHAR : EV_RXFLAG ));
            bReadStatus = WaitCommEvent(mHandle, &modemStatus, &osStatus);
        }

        if (bReadStatus)
        {
            cout << "Event occured sync" << endl;
            mProtocol.processEvent(terminate);

            if (terminate)
            {
                break;
            }
        }
        else
        {
            if (GetLastError() == ERROR_IO_PENDING)
            {
                fWaitingOnStat = TRUE;
            }
            else
            {
                cout << "Communication event failed with code: " << GetLastError() << endl;
                mProtocol.processTermination();
                stopped = true;
            }

            if ( fWaitingOnStat )
            {
                cout << dec << "WAITING FOR " << ( timeoutValue ? timeoutValue : INFINITE ) << endl;

                auto dwRes = WaitForSingleObject(osStatus.hEvent, timeoutValue ? timeoutValue : INFINITE);

                cout << "WAIT ENDED :)" << endl;

                if (dwRes == WAIT_OBJECT_0)
                {
                    //cout << "Event occured async" << endl;
                    mProtocol.processEvent(terminate);

                    fWaitingOnStat = false;

                    if (terminate)
                    {
                        mProtocol.processTermination();
                        break;
                    }
                }
                else if (dwRes == WAIT_TIMEOUT)
                {
                    cout << "Timeout" << endl;
                    mProtocol.processTimeout();

                    fWaitingOnStat = false;
                }
                else
                {
                    cout << "Communication event failed with code: " << GetLastError( ) << endl;
                    mProtocol.processTermination();
                    stopped = true;
                }

            }
        }

        stopped = mProtocol.getStopRequiredFlag();
        singleByteExpected = mProtocol.getWaitingForControlCharFlag();
        timeoutValue = mProtocol.getTimeout();
    } 
    while (!stopped);

    cout << "Stopped communication event loop ... " << endl;
}

1 个答案:

答案 0 :(得分:-1)

解决!根据UKMonkey的建议,行为是由我在控制台窗口上标记文本引起的。如果我单独留下它并且阻止我标记一个角色,它现在一定有效。我需要更改这些设置:)。感谢您对我的问题和答案感兴趣!