Можно ли перезапустить программу изнутри программы? [закрытый]

Я разрабатываю программу на C++, и было бы полезно использовать какую-то функцию, скрипт или что-то, что заставляет программу перезапускаться. Это большая программа, поэтому перезапуск всех переменных вручную займет у меня много времени...

Я не знаю, есть ли способ достичь этого или если это возможно.

9 ответов


Если вам действительно нужно перезапустить всю программу (т. е." закрыть "и" открыть "снова)," правильным " способом было бы иметь отдельную программу с единственной целью перезапуска вашей основной. AFAIK многие приложения с функцией автоматического обновления работают таким образом. Поэтому, когда вам нужно перезапустить основную программу, вы просто вызываете "перезапуск" и выходите.


вы можете использовать цикл в вашей :

int main()
{
    while(!i_want_to_exit_now) {
        // code
    }
}

или, если вы хотите фактически перезапустить программу, запустите ее из жгута проводов:

program "$@"
while [ $? -e 42 ]; do
    program "$@"
done

здесь 42 - это код возврата, означающий "перезагрузка, пожалуйста".

тогда внутри программы Ваш restart функция будет выглядеть так:

void restart() {
    std::exit(42);
}

на Unicies, или где-нибудь еще у вас есть execve и на главной странице указано, вы можете просто...убейте меня за использование atoi, потому что это вообще ужасно, за исключением такого случая.

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

int main (int argc, char** argv) {

  (void) argc;

  printf("arg: %s\n", argv[1]);
  int count = atoi(argv[1]);

  if ( getchar() == 'y' ) {

    ++count;

    char buf[20];
    sprintf(buf, "%d", count);

    char* newargv[3];
    newargv[0] = argv[0];
    newargv[1] = buf;
    newargv[2] = NULL;

    execve(argv[0], newargv, NULL);
  }

  return count;
}

пример:

$ ./res 1
arg: 1
y
arg: 2
y
arg: 3
y
arg: 4
y
arg: 5
y
arg: 6
y
arg: 7
n

7 | $

(7 был код возврата).

она не повторяется, ни явно петель-вместо этого, он просто называет себя, заменяя свое собственное пространство памяти с новой версией себя.

таким образом, стек никогда не переполнится, хотя все предыдущие переменные будут объявлены заново, как и при любом повторном вызове -getchar вызов предотвращает использование 100% CPU.

в случае самообновляющегося двоичного файла, так как весь двоичный файл (по крайней мере, на Unix-подобных, я не знаю о Windows) будет скопирован в память во время выполнения, то если файл изменится на диске перед execve(argv[0], ... вызов, новый двоичный файл, найденный на диске, а не тот же старый, будет запущен вместо.

как указывают @CarstenS и @bishop в комментариях, из-за уникального способа, которым был разработан Unix, открытые файловые дескрипторы хранятся через fork/exec, и в результате, чтобы избежать утечки открытых файловых дескрипторов через вызовы execve, вы должны либо закрыть их до execve или e, FD_CLOEXEC / O_CLOEXEC в первую очередь-более подробную информацию можно найти на блог Дэна Уолша.


это очень специфичный для ОС вопрос. В Windows вы можете использовать API перезапуска приложения или MFC Restart Manager. В Linux вы можете сделать exec()

однако большую часть времени есть лучшее решение. Вероятно, вам лучше использовать цикл, как это предлагается в других ответах.


Это звучит как неправильный подход, так как все ваше состояние является глобальным, и поэтому единственный четкий метод сброса всего (кроме ручного присвоения значений "по умолчанию" каждой переменной) - перезапустить всю программу.

вместо этого ваше состояние должно храниться в объектах (типа класса или любого другого). Затем вы можете создавать и уничтожать эти объекты, когда вы хотите. Каждый новый объект имеет новое состояние со значениями "по умолчанию".

Не боритесь с C++; используй его!


вам, вероятно, нужен цикл:

int main()
{
    while (true)
    {
        //.... Program....
    }
}

каждый раз, когда вам нужно перезапустить, позвоните continue; внутри цикла и для завершения программы используйте break;.


когда я разрабатываю системы реального времени, мой подход обычно является " производным main ()", где я пишу весь код, вызванный из реального main (), что-то вроде:

главная.программа СРР:

int main (int argc, char *argv[])
{
   while (true)
   {
       if (programMain(argc, argv) == 1)
           break;
   }
}

в programmain.cpp, где весь код написан:

int programMain(int argc, char *argv[])
{
    // Do whatever - the main logic goes here

    // When you need to restart the program, call
    return 0;

    // When you need to exit the program, call
    return 1;
}

таким образом, каждый раз, когда мы решаем выйти из программы, программа будет перезапущена.

Detail: все переменные, глобалы и логика должны быть записаны внутри programMain()- ничего внутри "main()" кроме перезапуска.

этот подход работает в системах Linux и Windows.


Мне кажется, что вы задаете неправильный вопрос, потому что вы недостаточно знаете о кодировании, чтобы задать правильный вопрос.

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

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

О, и 6 потоков не очень много! :)


в зависимости от того, что вы подразумеваете под "перезапуск" программы, я вижу несколько простых решений.

один заключается в том, чтобы встроить всю вашу программу в некоторый класс "программа", который по существу предоставляет некоторый цикл, который имеет вашу правильную программу. Когда вам нужно перезапустить программу, вы вызываете статический открытый метод "Restart", который снова запускает цикл.

вы также можете попытаться сделать системный вызов, который снова запустит вашу программу, и выйти. Как предложено в другом ответе, вы можете создайте программу-оболочку для этой единственной цели (и проверьте код возврата, чтобы узнать, следует ли выйти или перезапустить).

другой простой вариант-использовать goto. Я знаю, что люди возненавидят меня даже за упоминание об этом, но давайте посмотрим правде в глаза: мы хотим сделать простую программу, а не использовать красивую шаблонную. возвращение Гото гарантирует уничтожение, чтобы вы могли создать программу с меткой в начале, и некоторая функция "перезапуск", которая просто возвращается к началу.

какой бы вариант вы ни выбрали, документируйте его хорошо, поэтому другие(или вы в будущем) будут использовать один WTF меньше.

PS. Как упоминалось Алена, goto не будет уничтожать глобальные или статические объекты, то же самое будет для заключительного класса. Поэтому любой подход, который не включает запуск новой программы вместо текущей, должен либо воздерживаться от использования глобальных / статических переменных, либо предпринимать надлежащие действия для их повторной установки(хотя это может быть утомительно, как и в случае добавление каждого статического / глобального, вам нужно изменить процедуру перезапуска).