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

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

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

45

Решение

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

59

Другие решения

Вы можете использовать цикл в вашем main функция:

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

Или, если вы действительно хотите перезапустить программу, запустите ее из жгута:

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

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

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

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

На 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% загрузку процессора.

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

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

15

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

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

12

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

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

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

9

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

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

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

6

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

Программа main.cpp:

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

Программа main.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;
}

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

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

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

4

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

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

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

Ох и 6 тем не очень много! 🙂

2