Задать вопрос
hitakiri
@hitakiri

Почему запуск процесса через CreateProcess() может очень медленно выполняться?

Задача: запустить стороннюю программу и передать ей две строки.

Собственно функция:
int App::RunExternalProgramWithInput(const std::filesystem::path &programPath,
                                     const std::string &firstInput,
                                     const std::string &secondInput) {

  const std::string pp          = programPath.string();
  const std::string current_dir = programPath.parent_path().string();
  const std::wstring tmp_wstr(pp.begin(), pp.end());
  const std::wstring tmp_wpath(current_dir.begin(), current_dir.end());

  // Создание канала для ввода дочернего процесса
  HANDLE hChildStdinRd = nullptr, hChildStdinWr = nullptr;
  SECURITY_ATTRIBUTES saAttr  = {};
  saAttr.nLength              = sizeof(SECURITY_ATTRIBUTES);
  saAttr.bInheritHandle       = TRUE;
  saAttr.lpSecurityDescriptor = nullptr;

  if (!CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
    throw std::runtime_error("Не удалось создать канал для stdin");
  }

  // Настройка атрибутов процесса
  STARTUPINFO si  = {};
  si.cb           = sizeof(STARTUPINFO);
  si.hStdInput    = hChildStdinRd;
  si.dwFlags     |= STARTF_USESTDHANDLES;

  PROCESS_INFORMATION pi = {};

  // Запуск процесса
  if (!CreateProcess(tmp_wstr.data(),  // Имя исполняемого файла
                     nullptr,          // Аргументы командной строки
                     nullptr,          // Дескриптор процесса
                     nullptr,          // Дескриптор потока
                     TRUE,             // Наследование дескрипторов
                     0,                // Флаги создания
                     nullptr,          // Среда
                     tmp_wpath.data(), // Рабочая директория
                     &si,              // Настройки запуска
                     &pi               // Информация о процессе
                     )) {
    CloseHandle(hChildStdinRd);
    CloseHandle(hChildStdinWr);
    throw std::runtime_error("Не удалось запустить процесс");
  }

  // Закрытие дескриптора чтения (он уже используется дочерним процессом)
  CloseHandle(hChildStdinRd);

  // Передача первой строки
  std::string firstInputWithNewline = firstInput + "\n";
  DWORD dwWritten;
  if (!WriteFile(hChildStdinWr, firstInputWithNewline.c_str(), firstInputWithNewline.size(),
                 &dwWritten, nullptr)) {
    TerminateProcess(pi.hProcess, 1);
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
    CloseHandle(hChildStdinWr);
    throw std::runtime_error("Не удалось записать первую строку ввода");
  }

  // Передача второй строки
  std::string secondInputWithNewline = secondInput + "\n";
  if (!WriteFile(hChildStdinWr, secondInputWithNewline.c_str(), secondInputWithNewline.size(),
                 &dwWritten, nullptr)) {
    TerminateProcess(pi.hProcess, 1);
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
    CloseHandle(hChildStdinWr);
    throw std::runtime_error("Не удалось записать вторую строку ввода");
  }

  // Закрытие канала для сигнализации конца ввода
  CloseHandle(hChildStdinWr);

  // Ожидание завершения процесса
  WaitForSingleObject(pi.hProcess, INFINITE);

  // Получение кода завершения
  DWORD exitCode = 0;
  if (!GetExitCodeProcess(pi.hProcess, &exitCode)) {
    exitCode = 1; // Предполагаем ошибку, если не удалось получить код
  }

  // Очистка ресурсов
  CloseHandle(pi.hProcess);
  CloseHandle(pi.hThread);

  return static_cast<int>(exitCode);
}


Всё работает как надо. Но каждый раз выполнение этой функции происходит с разным количеством времени и очень медленно. Рекорд - ~8сек. Т.е. запускаем функцию и она выполняется очень медленно и с совершенно разным временем выполнения.

Запускается одна и та же программа, длина передаваемых строк фиксирована - 32 символа.

Нашел ещё одну странность - если запускать основное приложение от имени администратора, то никаких "подвисаний" нет. Всё работает быстро.

Вопрос: почему такое может просходить? и как это исправить?

П.с. это относится к вопросу косвенно, до этого писал такую же функцию на Go через
subProcess := exec.Command(readini.GetIniData().ExeFilePath)
stdin, err := subProcess.StdinPipe()

и всё работает отлично, никаких сбоем в работе и т.д. запускаемая программы теже. Т.е. выполняться всё может корректно, быстро и дело не в запускаемой программе.
  • Вопрос задан
  • 189 просмотров
Подписаться 1 Простой 6 комментариев
Пригласить эксперта
Ответы на вопрос 1
15432
@15432
Системный программист ^_^
Антивирус проверяет что вы там запускаете. Отключите проверку в реальном времени и попробуйте снова
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы