Как очистить содержимое scanf остановленного процесса?

Я использую fork, и дочерний процесс десять раз считывает данные от пользователя, используя scanf внутри цикла for. Однако родительский процесс отправляет сигнал SIGSTOP дочернему после 4 секунд сна, считывает значение от пользователя и печатает его. Но если пользователь ввел данные, но не нажал клавишу ввода для сканирования в дочернем процессе, родительский процесс читает, но печатает данные, записанные в дочернем процессе. Как мне предотвратить это.

ch=fork();
if(ch==0)
{
    for(i=0;i<10;i++)
    {
        fflush(stdin);
        scanf("%s",buf);
        printf("%d: %s\n",i,buf);
    }
}
else
{
    char buf2[100],cha;
    sleep(4);
    kill(ch,SIGSTOP);
    write(STDOUT_FILENO,"\nchld stopped\n",14);
    memset(stdin,0,sizeof(stdin));
    read(STDIN_FILENO,buf2,2);
    write(STDOUT_FILENO,buf2,2);

    kill(ch,SIGCONT);
    wait(SIGCHLD);
}

Таким образом, вывод, например, выглядит следующим образом:

a

0: a

b

1: b

ac (здесь я не нажимаю ввод и жду SIGSTOP)

ребенок остановился

tr (ввел данные для родителя и нажал Enter)

ac2: tr

c

3: с... и так далее

Итак, после ввода tr, почему мой родитель отображает ac?


person Emperor Penguin    schedule 15.09.2014    source источник


Ответы (3)


fflush(stdin) никогда не бывает правильным, хотя многие люди пытались это сделать. fflush предназначен только для вывода. Твой memset - чистое безумие. Аргумент wait не должен быть номером сигнала - это даже не правильный тип, поэтому вы должны были получить предупреждение, которое вы, по-видимому, проигнорировали.

Это легкие ошибки. Есть более глубокие концептуальные проблемы с тем, что вы пытаетесь сделать.

Поскольку вы не изменяли никаких настроек tty, tty находится в каноническом режиме, пока работает ваша программа. Это означает, что tty обрабатывает редактирование строки (возврат, Ctrl-U, Ctrl-W и т. д.) и ничего не отправляет программе до тех пор, пока строка не будет завершена.

Когда вы ввели неполную строку, эта неполная строка не находится в буфере стандартного ввода. Он находится в буфере tty. Он еще не принадлежит ни одному процессу. Вот почему ваш родительский процесс может прочитать строку, которая была частично напечатана, пока дочерний процесс пытался прочитать. У ребенка ничего не получалось.

Чтобы очистить буфер tty, это должно работать: отключите канонический режим; установить неблокирующий режим; читать в a до тех пор, пока не возникнет ошибка (EAGAIN/EWOULDBLOCK произойдет в неблокирующем режиме, когда tty больше нечего вам дать); снова включите блокировку и канонический режим. Идея состоит в том, чтобы потреблять все, что доступно в настоящее время, не дожидаясь большего. Код для выполнения отдельных шагов должен быть легко найден.

В общем, я сомневаюсь в разумности интерфейса, который предлагает пользователю возможность ввести информацию, а затем спонтанно прерывает чтение этой информации, чтобы прочитать что-то еще. Это заставит пользователей кричать на дополнительную подсказку ввода: ЭЙ! Я ПИШУ ЗДЕСЬ!

person Community    schedule 15.09.2014
comment
Хорошо... но все же не могли бы вы сказать мне, как очистить буфер tty? - person Emperor Penguin; 15.09.2014

Хорошо, я нашел решение.

Я использовал tcflush(): сбросить непереданные выходные данные, непрочитанные входные данные или и то, и другое.

tcflush(STDIN_FILENO,TCIFLUSH); строка непосредственно перед чтением в родительском элементе.

Я нашел решение здесь... Как сбросить непрочитанные данные из очереди ввода tty в системе UNIX?

person Emperor Penguin    schedule 15.09.2014

Это из-за функции read(), write(). Когда вы что-то вводите, не нажимая Enter. Он будет в stdinput, что бы ни было в stdinput, он будет считываться функцией read() в buf2, как указано в вашем примере. И что бы ни было в buf2, оно отправит на стандартный вывод с помощью write(). Вы можете увидеть разницу, когда комментируете функцию read(), write() или просто печатаете «buf2».

person Harsh Pratap    schedule 15.09.2014