На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
[!] Как относитесь к модерированию на этом форуме? Выскажите свое мнение здесь
Страницы: (2) [1] 2  все  ( Перейти к последнему сообщению )  
> Запустить стороннее приложение с атрибутами?
    Необходимо из написанной мной программы запустить другое приложение с 2мя атрибутами, аналогично команде:
    ExpandedWrap disabled
      start "" "C:\convecter_db_to_xml.exe" "C:\Users\Desktop\bdrelese" "7"


    Как это можно выполнить?
      В районе этого:
      ExpandedWrap disabled
        #include <stdio.h>
        #include <process.h>
         
        int main( int /*argc*/, char */*argv*/[] )
        {
            _spawnl( _P_WAIT, "C:\\convecter_db_to_xml.exe", "C:\\Users\\Desktop\\bdrelese", "7", NULL);
            return(0);
        }
        Выбирай - ShellExecute,CreateProcess,spawnl,spawnlp.....
          ShellExecute(Handle, NULL, (BdDir+"\\convecter_db_to_xml.exe").c_str(), "'C:\\Users\\Desktop\\bdrelese' '7'", NULL, SW_RESTORE);

          Я правильно атрибуты указал?
            Цитата Bas @
            Выбирай - ShellExecute,CreateProcess,spawnl,spawnlp.....


            Ребята, несколько расширю вопрос.
            1. Управляющей программой, написанной в C++ Builder, циклически запускается на счет тяжелая программа.
            2. На каждом шаге цикла тяжелая программа запускается с уникальными начальными данными, заданными в файле настроек.
            Этот файл настроек выступает в качестве параметра тяжелой программы в командной строке.
            3. После выполнения тяжелой программы управляющая программа сохраняет в создаваемых ею уникальных каталогах результаты работы тяжелой программы.
            4. Примечание: тяжелая программа на то и тяжелая, что работает она примерно 5 минут даже на относительно мощных машинах.

            Сейчас управляющая программа запускает тяжелую программу с параметром-файлом функцией
            ExpandedWrap disabled
              spawnl(P_WAIT, ...

            Не нравится то, что во время исполнения тяжелой программы управляющая программа примерно 5 минут недоступна! Выглядит, как зависшая!

            Вопрос: как сделать так, чтобы управляющая программа не теряла связи с операционной системой и в то же время не теряла контроль над тяжелой программой?
            Например, хочется во время работы тяжелой программы отметить в управляющей программе чекбокс "Прервать цикл выполнения тяжелой программы".

            Пока это все делаем так:
            1. Через ctrl+alt+del снимаем со счета управляющую программу.
            2. А потом останавливаем штатным образом тяжелую программу (она имеет графический интерфейс!)
              mkudritsky, запускай в отдельном потоке. А поток GUI оставь для управления.
                JoeUser, спасибо за помощь!

                Но я новичок в C++ и пока плохо ориентируюсь.
                А как технически запустить тяжелую дочернюю программу в отдельном потоке? Какими командами?

                Я пока прорабатывал такой вариант:
                ExpandedWrap disabled
                  spawnl(P_NOWAIT, ...);
                  ...
                  wait(NULL);


                Тут можно между командами spawnl и wait (cwait) выполнить какие-либо операторы.
                Но управляющая программа, дойдя до оператора wait, опять "зависает" до завершения тяжелой программы.
                А отследить факт того, что дочерняя тяжелая программа выполнена, можно, как я понял, только оператором wait (cwait).
                  Наверное, это немного сложнее будет.
                  Если запускать программу через функцию
                  ExpandedWrap disabled
                    BOOL ShellExecuteEx(LPSHELLEXECUTEINFO lpExecInfo);
                  она вносит изменения в структуру, заполняет поле ExeInfo.hProcess., благодаря чему можно узнать ID процесса функцией
                  ExpandedWrap disabled
                    DWORD PID = GetProcessID(ExeInfo.hProcess)
                  Посмотрите, возможно по завершении процесса, который Вы запустили, функция GetProcessID будет возвращать ноль. (а не его PID).

                  Т.е. в идеале программа сможет продолжать работу, но иметь возможность контролировать запущенный процесс.

                  Но с этим механизмом придется немного повозиться:
                  MSDN ShellExecuteEx function
                  MSDN SHELLEXECUTEINFO structure
                  MSDN GetProcessId function
                  Сообщение отредактировано: simsergey -
                    Цитата mkudritsky @
                    А отследить факт того, что дочерняя тяжелая программа выполнена, можно, как я понял, только оператором wait (cwait).

                    Если использовать для запуска функции ShellExecute или CreateProcess, возвращающие хэндл запущенного процесса (hProcess), то можно контролировать его завершение несколькими способами.
                    Самый простой - запустить таймер, в функции которого проверять завершение процесса по GetExitCodeProcess(hProcess,&ExitCode) && (ExitCode != STILL_ACTIVE).
                    Другой способ - использовать циклический вызов функции ожидания MsgWaitForMultipleObjects с pHandles = &hProcess и dwWakeMask = QS_ALLINPUT. Если функция возвращает WAIT_OBJECT_0 (= 0), то ожидаемый процесс завершен - выходим из цикла. Если возвращаемое значение = WAIT_OBJECT_0+1 (= 1), то пришло сообщение - вызываем Application->ProcessMessages и крутим цикл дальше.

                    Добавлено
                    Цитата simsergey @
                    Посмотрите, возможно по завершении процесса, который Вы запустили, функция GetProcessID будет возвращать ноль. (а не его PID).

                    Не будет. Информация о процессе сохраняется до тех пор, пока не будут закрыты все его хэндлы (в т.ч. и ExeInfo.hProcess)
                      Коллеги, спасибо всем за советы!
                      Скопирую их и распечатаю. Проверять все буду на рабочей неделе.
                      По результатам экспериментов обязательно отпишусь.
                        Народ, немного извиняюсь!
                        Как выяснилось, один из вариантов решения моей задачи, предложенный здесь, изложен в классической книге Архангельского по Builder 6 (книга 1).
                        (Ксатати, книга есть в Сети в *.pdf формате!)
                        Собственно, взяв оттуда пример + здешние советы и решил свою проблему:

                        ExpandedWrap disabled
                          bool res = CreateProcess(NULL, "MyHeavyTask.exe /Conf.txt",
                          NULL, NULL, false,
                          CREATE_NEW_CONSOLE |
                          HIGH__PRIORITY_CLASS,
                          NULL, NULL, &StartInfo, &ProcInfo));
                           
                          while (1) {
                           if (WaitForSingleObject(ProcInfo.hProcess, 500) == WAIT_0) break;
                          }


                        Собственно, в теле бесконечного цикла while один раз в 0.5 секунды можно контролировать управляющую программу.
                        Так что вопрос с "зависанием" управляющей программы во время счета тяжелой программы MyHeavyTask.exe решен.

                        Но тут же возник другой вопрос.
                        А если дочерняя тяжелая задача MyHeavyTask.exe зависает (такое очень редко, но бывает), то как отследить этот момент?
                        Может по тайм-ауту? Ведь нам примерно известно, сколько должна считаться тяжелая дочерняя задача.
                        А может есть какой другой способ отследить, что MyHeavyTask.exe завершилась с кодом, не равным 0?

                        P.S. Когда я запускал дочернюю задачу "умирающим" способом через
                        spawnl(P_WAIT,...
                        то spawnl возвращала -1 при зависании дочерней задачи.
                        Так что рычаги есть, чтобы проследить код завершения дочерней задачи. Но вот как?
                        Сообщение отредактировано: mkudritsky -
                          Зависание и завершение с ошибкой - это разные вещи. Если прога завершается (не важно с каким кодом), то твой цикл ожидания на Wait.. по любому прерывается, и код завершения, как уже было сказано, можно получить через GetExitCodeProcess. А зависание - это когда прога не завершается, либо потому, что впадает в некий бесконечный цикл, либо "ждет у моря погоды", попав в некий deadlock (блокировку) на объектах синхронизации\ожидания. При этом и твой цикл с Wait.. будет продолжать крутиться, и GetExitCodeProcess будет возвращать STILL_ACTIVE. Поэтому никакого другого способа определить зависание, кроме как по тайм-ауту, нет.

                          PS: Если ты в цикле ожидания собираешься вызывать Application->ProcessMessages, чтобы твоя прога хотя-бы перерисовывалась вовремя, или юзер смог нажать кнопку Отмена, то лучше использовать функцию MsgWaitForMultipleObjects, которой при желании тоже можно задать тайм-аут (хотя на требования перерисовки и на юзерские клики она и так среагирует).
                          Сообщение отредактировано: leo -
                            Вот крайняя версия фрагмента моего кода управляющей программы для запуска тяжелого приложения:

                            ExpandedWrap disabled
                              int iTime; // счетчик времени
                              DWORD iCod=14; // Код завершения процесса
                              CreateProcess(NULL, "MyHeavyTask.exe /Conf.txt",
                                  NULL, NULL, false,
                                  CREATE_NEW_CONSOLE |
                                  HIGH__PRIORITY_CLASS,
                                  NULL, NULL, &StartInfo, &ProcInfo));
                                  
                              while (1) { // Бесконечный цикл. Отслеживаются события во время счета тяжелой программы
                               DWORD ind = WaitForSingleObject(ProcInfo.hProcess, 500); // Раз в 0.5 секунды отслеживаются расчеты
                               iTime++; // Увеличивается на 0.5 сек счетчик времени выполнения тяжелой программы
                               UINT EndCode;
                               if (ind==WAIT_OBJECT_0) { // Если тяжелая программа завершилась корректно, то
                                GetExitCodeProcess(ProcInfo.hProcess, &iCod); // Получаем код завершения процесса
                                break; // и выходим из бесконечного цикла
                               }
                               Application->ProcessMessages();
                               if (iTime >840) { // Обработка отбоя по тайм-ауту в 7 минут
                                TerminateProcess(ProcInfo.hProcess, EndCode);
                                iCod=14;
                                break;
                               }
                              }


                            В чем здесь проблема?
                            Функция TerminateProcess не убивает дочерние зависшие процессы тяжелой программы.

                            Поясню суть проблемы.
                            Тяжелая программа MyHeavyTask.exe в свою очередь запускает на исполнение интерпретатор одной железки. Интерпретатор имеет тоже графический интерфейс, как и тяжелая задача.
                            Если тяжелая задача виснет, а интерпретатор - нет, то TerminateProcess снимает с выполнения тяжелую задачу, но не интерпретатор. И когда управляющая задача запускает на счет следующий экземпляр тяжелой задача, то вычислительный процесс продолжается нормально.

                            Однако, если зависает интерпретатор, то по тайм-ауту функцией TerminateProcess нормально снимается со счета тяжелая задача, но не висящий интерпретатор.
                            И при запуске следующего экземпляра MyHeavyTask.exe прерывается нормальное течение расчетов, т.к. интерпретатор висит!

                            Вот и возникает вопрос: как из управляющей программы снять со счета не только MyHeavyTask.exe, но и все ее дочерние процессы, включая интерпретатор.
                            Сообщение отредактировано: mkudritsky -
                              Цитата leo @
                              Вот и возникает вопрос: как из управляющей программы снять со счета не только MyHeavyTask.exe, но и все ее дочерние процессы, включая интерпретатор.

                              Очевидно найти все дочерние процессы и закрыть их по отдельности. Если процессы имеют окна, то можно найти их с помощью FindWindow по заголовку\стилю окна. Если можно найти окна, то перед тем как использовать тяжелую артиллерию в виде TerminateProcess, можно попробовать закрыть главное окно посылкой сообщения WM_CLOSE или WM_SYSCOMMAND c параметром SC_CLOSE (через SendMessageTimeOut, чтобы твоя прога сама не зависла). Или определить id потока, которому принадлежит окно ф-ей GetWindowThreadProcessID и через PostThreadMessage послать ему сообщение WM_QUIT. Если это не помогает, то остается открывать процесс и вызывать TerminateProcess.
                              Если не получается найти окно процесса, то можно перечислить дочерние процессы с помощью CreateToolhelp32Snapshot + Process32First\Next. Пример рекурсивного поиска и убийства дочерних процессов рассматривался недавно тут. (Там остались проблемы с "безопасным" убийством процесса через CreateRemoteThread, но если тебя устраивает TerminateProcess, то с созданием удаленного потока можно вообще не связываться)
                                Цитата mkudritsky @
                                Вот и возникает вопрос: как из управляющей программы снять со счета не только MyHeavyTask.exe, но и все ее дочерние процессы, включая интерпретатор.

                                Ctrl+Alt+Del :lol:
                                Может стоить подумать как разгрузить "тяжелую" задачу?
                                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                0 пользователей:


                                Рейтинг@Mail.ru
                                [ Script execution time: 0,0468 ]   [ 17 queries used ]   [ Generated: 28.03.24, 11:05 GMT ]