mercredi 27 mai 2015

C++ input is not blocking properly

I'm writing voice communicator. I have to control program from console, because we decided not to develop GUI - it's not important and it takes time. So, there is a thread which handles user commands from console:

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

Problem appears when I have to accept incoming call. I need the input so I can write yes or no. Thread which handles internet connection calls function which asks and gets answer (y/n). Next actions depend on what acceptCall function returned. I know it can cause trouble - many threads asking for input. So to prevent it, before thread calls this function, it terminates commandHandler thread(it's pthread and I cancel it - maybe not elegant, but works fine), gets input and then start again 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;
    }
}

And then something strange happens when I reject call and it starts commandHandler again. First getline from commandHandler is not waitng for input anymore. Loop starts working and no input is possible. I was trying all combinations of std::cin.ignore() and std::cin.clear(), all possible input functions. The best what I succeeded was blocking getline after another commandHandler start, but my commands didn't match any case in switch - commands were proper, but nothing, except one loop cycle happend after input. I'm going mad with this. I read hundreds of threads about C++ input but nothing helps me.

Aucun commentaire:

Enregistrer un commentaire