【问题标题】:C++ input is not blocking properlyC++ 输入未正确阻塞
【发布时间】:2015-05-27 07:54:57
【问题描述】:

我正在写语音通讯器。我必须从控制台控制程序,因为我们决定不开发 GUI——这并不重要,而且需要时间。所以,有一个线程处理来自控制台的用户命令:

void* ClientApp::commandHandler(void)
{
    std::string input;
    std::string connPort;
    std::string connAddr;
    std::map<std::string, int> mapStringValues;
    mapStringValues["connect to server"] = 1;
    mapStringValues["connect to host"] = 2;
    mapStringValues["disconnect from server"] = 3;
    mapStringValues["start call"] = 4;
    mapStringValues["end call"] = 5;
    mapStringValues["set TCP port"] = 6;
    mapStringValues["help"] = 7;
    mapStringValues["exit"] = 8;

    std::cout << "Write command" << std::endl;
    //int i = 0;

    while(true)
    {
        //std::cout<< ++i<<std::endl;
        std::getline(std::cin, input);

        switch(mapStringValues[input])
        {
            case 1:  //connect to server
                std::cout << "TODO: connect to server" << std::endl;
                break;

            case 2:  //connect to host
                std::cout << "IP:" << std::endl;
                std::getline(std::cin, connAddr);
                std::cout << "port:" << std::endl;
                std::getline(std::cin, connPort);
                connectToHost(connAddr, std::stoi(connPort));
                break;

            case 3:  //disconnect from server
                std::cout << "TODO: disconnect from server" << std::endl;
                break;

            case 4:  //call
                if(callInProgres == true)
                {
                    break;
                }
                networkController->udpConnect();
                startCallViaNet();
                break;

            case 5:  //end call
                endCallViaNet();
                break;
            case 6: 
                break;
            case 7:
                showCommands();
                break;
            case 8:
                audioPlayer->stopThread();
                audioRecorder->stopThread();
                networkController->stopSendUDPThread();
                networkController->stopRecvUDPThread();
                networkController->stopRecvTCPThread();
                networkController->shutdownUdpConnection();
                networkController->shutdownTcpConnection();
                exit(0);
                break;
        }
    }
}

当我必须接听来电时出现问题。我需要输入,所以我可以写是或否。处理互联网连接调用函数的线程询问并获得答案(是/否)。接下来的操作取决于 acceptCall 函数返回的内容。我知道这会引起麻烦 - 许多线程要求输入。所以为了防止它,在线程调用这个函数之前,它会终止 commandHandler 线程(它是 pthread,我取消它 - 可能不优雅,但工作正常),获取输入然后重新启动 commandHandler:

int ClientApp::acceptCall(std::string ip)
{
    std::cout << "Start call from "<<ip<<"? (y/n)" << std::endl;
    char c = (char)getchar();  /* std::cin, getline, scanf... - I tied it*/
    if(c == 'y'){
        return 0;
    }
    else{
        return -1;
    }
}

然后当我拒绝呼叫并再次启动 commandHandler 时发生了一些奇怪的事情。 commandHandler 的第一个 getline 不再等待输入。循环开始工作,无法输入。我正在尝试所有可能的输入函数 std::cin.ignore() 和 std::cin.clear() 的所有组合。我成功的最好的方法是在另一个 commandHandler 启动后阻塞 getline,但我的命令与 switch 中的任何情况都不匹配 - 命令是正确的,但没有,除了输入后发生了一个循环循环。我要疯了。我阅读了数百个关于 C++ 输入的线程,但没有任何帮助。

【问题讨论】:

  • 您能尝试创建一个Minimal, Complete, and Verifiable Example 并展示给我们看吗?并且还向我们展示了一些导致该行为的实际输入?
  • 执行这种情况需要很多代码,我要到下午 6 点才能访问我的计算机:/

标签: c++ multithreading c++11 input console-application


【解决方案1】:

让我猜猜,当你得到getchar 的输入时,你会用换行符结束输入吗?然后getchar 读取并从缓冲区中提取您输入的字符,但留下换行符以供下一个输入操作读取。

如果有输入应该被忽略,那么标准的 C++ 方法就是调用流函数调用,std::istream::ignore。请点击链接,它显示了如何使用它的示例。

【讨论】:

  • 就像我在第二个函数的评论中写的那样 - 我尝试了 getline 等。我使用的没有区别,我也尝试使用不带参数的忽略,大小和 '\n',最大值缓冲区大小等
  • @Franek std::getline 立即返回的唯一方法是输入缓冲区中有完整的行,在流上设置了一些错误状态。你检查过这些吗?
  • 我应该在它进入循环之前检查是否有错误状态吗?然后做什么?让我们假设,在整个程序中 getline 是唯一的输入方式。你能写一些示例代码吗?
  • @Franek 您可能应该将其作为std::getline 调用的一部分,例如if (!std::getline(...)) { /* something's wrong */ }
  • 我发现了一些痕迹。您认为 BSD 套接字接受函数和标准输入之间可能存在某种关联吗?我在接受函数后调用acceptCall,这样我就可以接受或拒绝连接。当它在接受后调用 getline 时,它​​从 cin 中获取一些东西(它不是空的)并将所有错误标志设置为 1。
猜你喜欢
  • 1970-01-01
  • 2012-12-29
  • 2010-10-01
  • 2011-03-10
  • 2016-07-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多