Как я могу заставить новый поток «взять на себя» stdin?

#c #io #stdin

#c #io #стандартный интерфейс

Вопрос:

В программе, которую я пишу, у меня есть основной поток, который содержит цикл для приема ввода с консоли. Однако в какой-то момент создается новый поток, который также пытается читать из stdin. Существует переменная, которая указывает, что этот другой поток запущен, но fgets все еще ожидает ввода в основном потоке, поэтому первый консольный ввод, введенный после запуска нового потока, ошибочно считывается основным потоком вместо нового потока.

Есть ли какой-то способ решить эту проблему?

Одна вещь, которую я пробовал, это (в основном потоке):

 while(foo) {
   if(busy) continue;
   fgets(input,200,stdin);
   if(busy) {
      fputs(input,stdin);
   } else {
      // do whatever was supposed to be done with input intended for main thread
   }
}
  

Но, похоже, я неправильно понимаю, как работают потоки, потому что другой вызов fgets не считывает данные, записанные через fputs.

Комментарии:

1. Почему вы пытаетесь это сделать? Вы уверены, что нет лучшего дизайна, который сохраняет все операции ввода-вывода в одном потоке?

2. Это было бы идеально. Наверное, у меня возникли проблемы с видением леса за деревьями. Я попробую это.

Ответ №1:

Создайте логическую переменную, защищенную соответствующим примитивом синхронизации. Инициализируйте его значением false. Когда потоку нужно задать пользователю вопрос и получить ответ, дождитесь, пока переменная станет «ложной» (в соответствии с выбранным вами примитивом синхронизации), а затем установите для нее значение true. Выполните все выходные данные и получите все необходимые входные данные. Затем установите для переменной значение ‘false’ и разблокируйте все ожидающие потоки (в зависимости от выбранного вами примитива синхронизации).

Для pthreads, вероятно, лучше всего использовать переменную mutex и condition. Для Windows, вероятно, лучше всего использовать критический раздел и событие автоматического сброса.

В вашем вопросе не хватает некоторых деталей, которые могут предложить другой ответ. Как пользователь должен взаимодействовать с программой, когда он не может быть уверен, какой из двух отдельных путей кода получит ввод, который он вводит? Если он что-то вводит, а затем нажимает «enter», какой путь кода он переходит, по-видимому, зависит от того, нажмет ли он «enter» до того, как другой поток будет готов или нет, что, по-видимому, делает программу непригодной для использования. Почти в каждом реалистичном случае вам нужно будет запросить пользователя, а затем дождаться ответа, а затем отпустить ввод и вывод вместе.

Комментарии:

1. Спасибо за информацию! Это определенно будет полезно в какой-то момент, но для этой программы я переработал, чтобы только один поток имел дело с stdin.

Ответ №2:

Для потомков, вот как я решил это.

Вместо того, чтобы оба потока ожидали ввода с консоли, теперь только один поток ожидает ввода и делегирует обработку этого ввода функциям, специфичным для состояния программы.

Приведенный выше фрагмент становится:

 while(foo) {
   fgets(input,200,stdin);
   if(busy) {
      busyStuff(input);
   } else {
      nonBusyStuff(input);
   }
}
  

и никакой другой pthread, у которого есть вызов fgets, никогда не создается.