Как специально пропустить cin в С++?

Мне нужно запустить цикл while и принимать в него ввод всякий раз, когда есть ввод. Я не новичок в C++, но это препятствие довольно сложное. Из-за соглашения о неразглашении (это школьный проект, по-видимому, какой-то секретный материал), я могу показать вам только тестовый пример.

Я хватался за соломинку, пытаясь решить проблему; попробуйте поймать, cin.get, cin.peek, if(cin.peek){}. Если кто-нибудь может указать мне в правильном направлении, я был бы очень благодарен!

Программа не критична ко времени, но функцию нужно вызывать с фиксированным интервалом. Не обязательно, чтобы код был переносимым, представлял собой комбинацию while-cin или что-то в этом роде; код будет работать только на ПК с Windows 7 или Windows 8, по крайней мере, с двухъядерным процессором.

#include <iostream>
#include <ctime>

using namespace std;

int main()
{
    int input = 0;
    int pastTime, nowTime;
    pastTime = nowTime = time(0);

    cin >> input;
    while(input != -1)
    {
        if(input == 1)
        {
            cout << "Entered 1" << endl;
            //To be done instead of the two 'elses', 
            //bypassing interval-dependant code
        }
        else if(input == 2)
        {
            cout << "Entered 2" << endl;
            //To be done instead of the interval-dependant code
        }
        else if(pastTime == (nowTime - 5))
        {
            cout << "Nothing entered." << endl;
            //Needs to be done with a fixed interval.
        }
        nowTime = time(0);
        cin >> input;
    }
return 0;
}

Решение было основано на ссылке Джеймса Бейлби:

// This program is based on counter.cpp from Boost\lib\thread\tutorial

#include <boost/thread/thread.hpp>
#include <iostream>
#include <ctime>

int timeNow = time(0);
int timePast = time(0);

void fct_one()
{
    while(1) //keeps running all the time
    {
        if(timePast == (timeNow - 3)) // only executed once every three seconds
        {
            //do some stuff
            timePast = time(0);
        }
        timeNow = time(0); // time is continuously updated 
    }
}

void fct_two()
{
    int input = 0;
    int timeTemp = time(0);
    while(1) //keeps running all the time
    {
        std::cin >> input; // cin blocking for input
        if(input == 1)
        {
            //do some stuff
        }
        if(input == 2)
        {
            //do some stuff
        }
        if(input == -1)
        {
            std::cout << "Program is done. ";
            system("pause");
            exit(1);
        }
    }
}

int main()
{
    boost::thread_group threads;
    threads.create_thread(&fct_one)
    threads.create_thread(&fct_two);
    threads.join_all();
    return 0;
}

person Community    schedule 07.11.2012    source источник
comment
Вы хотите сказать, что хотите тайм-аут ожидания ввода с терминала?   -  person user7116    schedule 07.11.2012
comment
Существует некоторое обсуждение неблокирующих вызовов std::cin @ bytes.com/topic/c/answers/841283-how-make-non-blocking-call-cin, но в результате, вероятно, проще сохранить цикл, как указано выше, и создать второй поток, который выполняет вашу работу с фиксированным интервалом.   -  person James Beilby    schedule 07.11.2012
comment
@ahenderson вам не хватает апострофа и буквы е ;-)   -  person Rook    schedule 07.11.2012
comment
Если этот код не должен быть переносимым, вы можете обнаружить, что существуют более эффективные способы выполнения неблокирующего или асинхронного ввода-вывода с использованием подходящей библиотеки для конкретной платформы, а не с использованием абстракции iostream относительно высокого уровня.   -  person Rook    schedule 07.11.2012
comment
Что ж, во встроенных системах у вас часто возникают подобные проблемы, и обычно вы решаете их с помощью дополнительного потока.   -  person Zane    schedule 07.11.2012
comment
Альтернативой дополнительному потоку является переключение устройства в неблокирующий режим, если это возможно, как описано для cin в ссылке Джеймса.   -  person Zane    schedule 07.11.2012
comment
sixlettervariables: Нет, я хочу продолжать цикл и иметь возможность вводить данные в cin, хотя это решение кажется практически невозможным. Джеймс Бейлби: Спасибо. Кажется, это именно то, что я искал в течение часа в Google. ахендерсон: Счастлив? :) Спасибо. Я перечитал вопрос несколько раз. Не забудьте вычитать заголовок (если есть) в следующий раз. Рук: Я думаю, что метод в ссылке Джеймса Бейлби в значительной степени делает то же самое, только совершенно другим способом. Зейн: Несколько тредов кажется подходящим вариантом. Спасибо :)   -  person    schedule 08.11.2012


Ответы (2)


Я бы полностью отделил ввод чтения от cin и выполнение функции тайм-аута по умолчанию. Вам понадобится что-то вроде фонового потока, который выполняет функцию по умолчанию в зависимости от временного интервала. Чтобы обработать первые два случая, вам нужно сигнализировать потоку о пропуске следующего выполнения (если это действительно необходимо) и просто вызывать любую функцию, которую вы хотите, или ничего не делать.

person πάντα ῥεῖ    schedule 07.11.2012
comment
Спасибо, я буду работать над этим в сочетании с отличной ссылкой Джеймса Бейлби. Я никогда не использовал более одной темы, и в моем учебнике она не упоминается ни единым словом - так что я, очевидно, новичок по сравнению с вами, ребята. - person ; 08.11.2012

Простой ответ — поместить код, который выполняется с некоторым интервалом, в другой поток. Поскольку вы отметили, что это Windows, вы можете использовать Очередь по таймеру:

Начните с подпрограмм, чтобы начать и остановить работу, зависящую от времени:

HANDLE Start(HANDLE hTimerQueue)
{
    DWORD timerMS = 5000; /* every 5 seconds */
    HANDLE hTimer;
    if (!CreateTimerQueueTimer(&hTimer, 
          hTimerQueue,
          (WAITORTIMERCALLBACK)timerWork,
          /*lpParam*/NULL,
          /*start in ___ ms:*/0,
          /*run every __ ms:*/timerMS,
          /*flags*/0))
    {
        return NULL;
    }

    return hTimer;
}

BOOLEAN Stop(HANDLE hTimerQueue, HANDLE hTimer)
{
    if (!DeleteTimerQueueTimer(hTimerQueue,
        hTimer,
        /*wait for our timer to complete*/INVALID_HANDLE_VALUE))
    {
        return FALSE;
    }

    return TRUE;
}

Затем поместите свою работу, зависящую от времени, в свой собственный обратный вызов:

VOID CALLBACK timerWork(PVOID lpParam, BOOLEAN TimerOrWaitFired /*ignored*/)
{
    for (int ii = 0; ii < 10; ++ii) {
        std::cout << "timer work: " << ii << std::endl;
        Sleep(250);
    }
}

Наконец, интегрируйте их в свой рабочий процесс:

int main(int argc, char* argv[])
{
    HANDLE hTimerQueue = CreateTimerQueue(hTimerQueue);
    if (NULL == hTimerQueue) return -1;
    HANDLE hTimer = Start(hTimerQueue);
    if (NULL == hTimer) return -1;

    /* our timed callback is now running in the background */
    int input = 0;
    std::cin >> input;
    while(input != -1)
    {
        if(input == 1)
        {
            if (Stop(hTimerQueue, hTimer)) {
                std::cout << "Entered 1" << std::endl;
                if (NULL == (hTimer = Start(hTimerQueue))) return -2;
            }
        }
        else if(input == 2)
        {
            if (Stop(hTimerQueue, hTimer)) {
                std::cout << "Entered 2" << std::endl;
                if (NULL == (hTimer = Start(hTimerQueue))) return -2;
            }
        }

        std::cin >> input;
    }

    DeleteTimerQueue(hTimerQueue);
    return 0;
}
person user7116    schedule 07.11.2012
comment
По сравнению с тем немногом, что я читал о многопоточности, ваше решение кажется немного излишним для моего приложения. Спасибо за помощь и ответ - я буду использовать его, если многопоточность убьет меня;) - person ; 08.11.2012
comment
Я могу добавить простой пример работы с потоками Джейн, если вам это нужно. Трюк будет заключаться в правильной остановке и возобновлении зависящего от времени кода. - person user7116; 08.11.2012
comment
Спасибо, но я научился работать с Boost:Thread. Обновит вопрос, чтобы отразить, что он был решен. - person ; 08.11.2012
comment
@CarstenNielsen: круто, но не нужно редактировать заголовок или свой пост, чтобы сказать «Решено». Все, что вам нужно сделать, это нажать на зеленую галочку, как вы это сделали. - person user7116; 08.11.2012
comment
Мне просто нравится оставлять ответ любому, кто ищет ответ. Знаете, на всякий случай ;) - person ; 09.11.2012