STDIN кажется сломанным после вызова "system", вызывающего mpiexec

Это мой первый пост здесь, поэтому прошу прощения за любые вопросы форматирования.

У меня есть интерактивная программа, которая порождает внешние процессы и контролирует их IO. Все работает нормально, пока я не создаю что-то с помощью mpiexec, после чего STDIN, кажется, ломается.

Я понимаю, что это будет трудно воспроизвести большинству людей, но если кто-то увидит что-то очевидное или узнает об этой проблеме... пожалуйста, помогите!

Вот фрагмент:

int main( ... )
{
  std::string choice;
  while(std::getline(std::cin,choice)){
     if(!choice.empty()){
       if(choice == "Parallel"){
        system("mpiexec ./aprogram");
       }
       if(choice == "Serial"){
        system("./aprogram");
       }
       // Now the external process is done... so far, so good
       std::cout << "Program is done. Press ENTER to continue." 
                 << std::endl;
       // This next line *works* if the external process was serial
       // But *fails* when "mpiexec" was invoked 
       std::getline(std::cin,choice);
       if(std::cin.eof()){
         std::cout << "STDIN has been closed." << std::endl;
         exit(1);
       }
     }
  }
} 

Я пробовал много разных вещей, например, трубы, явное разветвление, тщательное управление дескрипторами. Самое странное, что если я дублирую и сохраняю stdin, а затем восстанавливаю его после возвращения "mpiexec", то я больше не получаю EOF для std:: cin, а вместо этого std::getline(std::cin,...) больше не блокирует! Программа входит в бесконечный цикл, считывающий нулевые байты из std:: cin в вызове std:: readline.

Если, пока внешний процесс выполняется под mpiexec, я помещаю кучу данных в std::cin (например, печатая), то последующие вызовы std:: readline правильно анализируют строки данных, которые я там застрял, но еще раз... как только он закончил чтение этих данных, он просто продолжает бесконечный цикл (т.е. не блокирует std::readline(std::cin,..), даже если нет данных для чтения! Тьфу. Так раздражает.

Любая помощь высоко ценится.

Ура!

2 ответа

Я думаю, что я исправил вашу проблему, для меня или вызов Serial или Parallel заблокирован, и я думаю, что это был тест std::cin.eof(),

  std::getline(std::cin,choice);
  if(std::cin.eof()){         
     td::cout << "STDIN has been closed." << std::endl;
     exit(1);
   }

Однако, изменив это на std::cin.get(), прекрасно работает как для параллельного, так и для последовательного запуска.

   if(std::cin.get()) {
     std::cout << "STDIN has been closed." << std::endl;
     exit(1);
   }

Работает на моей системе.

Редактировать: отчет об ошибках перемещен на GitHub.

Хорошо, это не совсем ответ, но у меня недостаточно репутации, чтобы комментировать вопрос, по-видимому.

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

У Mpich действительно есть ошибка, когда он устанавливает O_NONBLOCK флаг на файловых дескрипторах stdout / stderr mpirun в обычных режимах. Эти настройки сохраняются после mpirun выходы. Тем не менее, эта ошибка, как правило, не появляется, потому что bash имеет код, который отключает флаги неблокирования подключенных потоков после каждой выполняемой команды, если это необходимо.

Код, который непосредственно отвечает за mpirunв alloc_fwd_hash в src/pm/hydra/utils/sock.sock.c, Он запускается кодом в таких местах, как src/pm/hydra/tools/bootstrap/external/external_common_launch.c в HYDT_bscd_common_launch_procs функция, где есть некоторый шаг регистрации демультиплексора, который включает в себя обратный вызов HYDT_bscu_stdio_cb что в конечном итоге вызываетalloc_fwd_hashфункция. Есть пара других похожих частей кода, которые также настраиваютHYDT_bscu_stdio_cbобратный вызов и, по моему чтению кода, должен вызвать ту же проблему. Я не знаю достаточно о mpich, чтобы понять, какая часть виновата, но я считаю, что для mpich неуместно устанавливать дескрипторы файлов TTY в неблокирующем режиме.

Вы можете вызвать эту ошибку, запустив mpirunна OS X используя сборку Homebrew bash. Bash Homebrew - это версия 4.4, которая, по причинам, не совсем понятным для меня, кажется, не активирует фрагмент кода, который очищаетO_NONBLOCK флаг. Версией bash по умолчанию для OSX является версия 3, которая очищает флаг, предотвращая появление ошибки. Версия Bash 4 для Macports также обнаруживает ошибку.

Другие вопросы по тегам