2016-10-13 6 views
41

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

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

+37

Независимо от того, что вы делаете, не вызывайте 'main()' в свой код. – NathanOliver

+14

"перезапуск всех переменных вручную" Wut? – Treycos

+5

Считаете ли вы использование цикла? –

ответ

53

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

+0

Итак, было бы достаточно иметь две программы, которые звонят друг другу и выходят, когда требуется перезапуск, не так ли? –

+6

Они не называют друг друга; вызывающий - это в основном цикл, который вызывает второй, ждет его выхода, а затем снова вызывает его. «Реальная» программа ничего не знает о вызывающем; он просто выходит. – chepner

+3

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

6

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

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

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

+1

Не рекомендуется кем? – StoryTeller

+0

У вас есть ссылка? Можно было бы разумно прочесть рассуждение. И может улучшить ваш ответ. – StoryTeller

+0

Это один парень, с одним мнением. Утверждение, что эти функции «не рекомендуются» на основе этого мнения бесполезны. Лично я не согласен с Питером, но его мнение действительно; это просто не единственный. –

42

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

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

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

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

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

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

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

Первое решение не будет работать, если программа не написана хорошо. Например, если он содержит утечку памяти, он не будет освобожден, просто пройдя цикл. Однако другое решение, которое вы предоставили, будет решать даже такие проблемы. –

+16

@HumamHelfawi Если у программы есть утечки памяти, они должны быть исправлены так или иначе, независимо от того, выполняется ли она в цикле или нет. С той же логикой вы могли бы сказать, что первый подход не очень хорош, потому что если у программы есть UB, у нее будет UB несколько раз ... – user463035818

+3

@ tobi303 Нет, это не хорошо. Однако фраза «перезапустить программу» означает нечто вроде «очистки всех мусора» или другими словами: «очистите все и начните свежие». Поэтому я полагал, что очистка любых утечек является частью этого ... Во всяком случае, я с вами, что никто не оставляет утечек и использует метод перезагрузки для его решения. Я просто подумал, что стоит упомянуть –

12

Это очень вопрос OS-специфичны. В Windows вы можете использовать Application Restart API или MFC Restart Manager. В Linux вы можете сделать exec()

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

15

На Unicies, или где-нибудь еще у вас есть execve и он работает как the man page specifies, вы можете просто ... убить меня за использование 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 в первую очередь - более подробную информацию можно найти на странице Dan Walsh's blog.

+3

Что относительно ресурсов, которые могли быть приобретены? –

+1

@CarstenS Они, вероятно, просочились. См. Http://danwalsh.livejournal.com/53603.html – bishop

+0

@CarstenS Хороший вопрос, мне нужно будет провести некоторое тестирование. Моя догадка заключается в том, что куча просто исчезает вместе с * всем остальным программной памятью * и перезаписывается «новой» кучей, поэтому они снесены, как когда программа выходит. – cat

1

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

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

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

Другой простой вариант - использовать goto. Я знаю, что люди будут ненавидеть меня за то, что даже упомянули об этом, но давайте посмотрим правде в глаза: мы хотим сделать простую программу, а не использовать красивый шаблон. Goto going back guarantees destruction, чтобы вы могли создать программу с меткой в ​​начале, а также некоторая функция «Перезагрузка», которая только начинается с начала.

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

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

+2

'goto' не уничтожит глобальные и статические объекты. – alain

8

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

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

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

4

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

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

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

Программный код.каст, где написано код:

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.

+0

Разве это не повторилось бы снова и снова вызовет programMain? Вам нужно что-то сломать внешнюю петлю. Я не парень из C++, но я был бы удивлен, если бы это сделал код возврата, особенно если вы его нигде не используете ... – Alex

+0

Да, идея состоит в том, чтобы снова вызвать 'programMain()', перезапустить вся логика. Действительно, «return 1» может выйти из цикла. Отредактировано .... – Mendes

+0

Теперь ясно. Хотя я лично все же предпочел бы подход отдельной мини-программы, чтобы перезагрузить полностью/чисто ... – Alex

2

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

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

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

О, и 6 нитей не очень много! :)

+0

Конечно, у меня есть чему поучиться и улучшить. Я не хочу перезапускать «целую» последовательность вызовов/местоположений, я хочу перезапустить все приложение, 7 файлов, смещение датчиков ... Я хочу перезапустить свою программу, потому что это то, что мне нужно. Выполнение теплого перезапуска требует слишком большого количества кода и усилий для меня, и я ничего не получаю от этого, просто усложняю больше кода. –

+0

Вы хотите закрыть файлы, затем снова открыть их и повторно инициализировать переменные? Затем закройте файлы после пропущенного вызова. И используйте цикл, чтобы вернуться назад и снова выполнить свою инициализацию. Я не пытаюсь быть грубым, но нет ситуации, когда перезапуск приложения является разумной альтернативой простому циклу. Если это проект uni, вы *** получите более низкий класс, если продемонстрируете отсутствие технических возможностей. Я не пытаюсь быть грубым, я пытаюсь указать вам в сторону того, что дает вам хорошую оценку. :) – Graham