2016-10-13 8 views
41

C++ 프로그램을 개발 중이며 일부 기능, 스크립트 또는 프로그램을 다시 시작하는 프로그램을 사용하는 것이 유용 할 것입니다. 그것은 큰 프로그램이므로 수동으로 모든 변수를 다시 시작하면 시간이 오래 걸릴 것입니다 ...프로그램 내부에서 프로그램을 다시 시작할 수 있습니까?

이 방법을 사용할 수 있는지 또는 가능한지 모르겠습니다.

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

당신이 다시 시작 루프 내에서 continue;을 호출하고 프로그램을 종료 할 때마다, break;를 사용

+37

무엇을 하든지 코드에서'main()'을 호출하지 마십시오. – NathanOliver

+14

"모든 변수를 수동으로 다시 시작"Wut? – Treycos

+5

루프 사용을 고려 했습니까? –

답변

53

전체 프로그램을 다시 시작해야하는 경우 (즉, '닫기'및 '다시 열기') '기본'프로그램을 다시 시작하는 것이 유일한 방법입니다. AFAIK는 자동 업데이트 기능이있는 많은 응용 프로그램을이 방법으로 작동시킵니다. 따라서 메인 프로그램을 재시작해야 할 경우 "재시동"프로그램을 호출하고 종료하십시오. 당신이 실제로 프로그램을 다시 시작하려는 경우 하네스에서 실행,

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

을 또는 :

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

42이 반환이다

+0

그래서 서로를 호출하고 재시작 할 때 종료하는 두 개의 프로그램이 있으면 충분합니까? –

+6

그들은 서로를 호출하지 않습니다. 호출자는 기본적으로 두 번째 호출을 호출하고 종료 할 때까지 기다린 후 다시 호출하는 루프입니다. "진짜"프로그램은 호출자에 대해 아무 것도 모른다. 그냥 나간다. – chepner

+3

그리고 작업자는 감시 코드에 의해 다시 시작할지 여부를 종료 코드를 통해 알릴 수 있습니다. –

6

당신은 아마 루프가 필요합니다.

+1

누구로부터 추천하지 않습니까? – StoryTeller

+0

링크가 있습니까? 추론은 읽기 좋을 것입니다. 그리고 당신의 대답을 향상시킬 수 있습니다. – StoryTeller

+0

한 사람의 의견입니다. 그 의견을 근거로 이러한 기능이 "권장되지 않음"이라고 주장하는 것은 도움이되지 않습니다. 개인적으로 나는 베드로와 의견이 다르지만 그의 견해는 유효합니다. 밖에있는 게 아닙니다. –

42

당신은 당신의 main 함수에서 루프를 사용할 수 있습니다 코드는 "restart, please"를 의미합니다.

그런 프로그램 내부에 restart 기능은 다음과 같을 것이다 :

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

프로그램이 잘 작성되지 않으면 첫 번째 해결 방법이 제대로 작동하지 않습니다. 예를 들어, 메모리 누수가있는 경우 단순히 루프를 통과하여 해제되지 않습니다. 그러나, 당신이 제공 한 다른 솔루션도 이러한 종류의 문제를 처리 할 것입니다. –

+16

@HumamHelfawi 프로그램에 메모리 누수가있는 경우 루프에서 실행되는지 여부에 관계없이 아무 래도 수정해야합니다. 동일한 논리로 첫 번째 접근법이 좋지 않다는 것을 말할 수 있습니다. 프로그램에 UB가 있으면 여러 번 UB가 생기기 때문에 ... – user463035818

+3

@ tobi303 아니요. 그러나 "프로그램을 다시 시작하십시오"라는 말은 "모든 쓰레기를 깨끗하게하는 것"과 같은 의미입니다 : "모든 것을 깨끗하게하고 신선하게 시작하십시오."그래서 나는 누출을 청소하는 것이 그것의 일부라고 생각합니다 ... 어쨌든, 나는 아무도 누출을 풀지 않고 다시 시작하는 방법을 사용하여 해결합니다. 방금 언급 한 가치가 있다고 생각했습니다. –

12

이것은 매우 OS 관련 질문입니다. Windows에서는 Application Restart API 또는 MFC Restart Manager을 사용할 수 있습니다. 리눅스에서는 할 수있다 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 % CPU 사용을 방지합니다.

자동 업데이트 바이너리의 경우 런타임시 메모리에 전체 바이너리 (적어도 Unix가 좋아요, Windows에 대해 알지 못함)가 복사되므로 디스크의 파일이 변경되면 execve(argv[0], ... 호출 전에 디스크에있는 새 바이너리가 이전의 동일한 바이너리가 아닌 대신 실행됩니다.

으로 @CarstenS 인해 유닉스가, 파일 기술자가 fork/exec에 걸쳐 유지되어 설계되었다하는 독특한 방식으로, 코멘트에 지적 @bishop 및 전역 파일 기술자 누출 방지하기 위하여 결과 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를 덜 사용하게하십시오.

추신. alain으로 언급했듯이 goto은 전역 객체 나 정적 객체를 파괴하지 않으며 클래스를 둘러싸는 데에도 동일하게 적용됩니다. 따라서 현재의 프로그램 대신에 새로운 프로그램을 시작하는 것을 포함하지 않는 접근법은 전역 변수/정적 변수를 사용하지 않거나 적절한 조치를 취하여 다시 설정해야합니다 (각 정적/전역 변수의 추가와 마찬가지로 지루할 수도 있음) 다시 시작 루틴을 수정해야합니다.

+2

'goto'는 전역 객체와 정적 객체를 파괴하지 않습니다. – alain

8

모든 상태가 전역 변수 인 것처럼 잘못된 접근법처럼 들리므로 모든 변수를 수동으로 할당하는 것 이외에 모든 것을 재설정하는 유일한 방법은 전체 프로그램을 다시 시작하는 것입니다 .

대신 상태는 객체 (클래스 유형 또는 기타)로 유지되어야합니다. 그런 다음 언제든지이 오브젝트를 자유롭게 작성하고 파괴 할 수 있습니다. 각각의 새로운 객체는 "default"값을 가진 새로운 상태를가집니다.

C++과 싸우지 마십시오. 그걸 써! 내가 실시간으로 시스템을 개발할 때

4

내 접근 방식은 보통이다 "파생 주()"나는) (진짜 메인에서 호출 모든 코드를 작성하는 경우, 같은 :

MAIN.CPP 프로그램 :

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

프로그래밍 방식입니다.모든 코드가 기록 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 시스템에서 모두 작동합니다.

+0

그냥 돌아가서 programMain을 다시 호출하지 않겠습니까? while while 루프를 깨뜨릴 무언가가 필요합니다. 나는 C++ 녀석이 아니지만, 1 개의 리턴 코드가 그 일을했다면 놀라실 것이다. 특히 여러분이 어디서나 사용하지 않는다면 ... – Alex

+0

네, 생각은'programMain()'을 다시 호출하고, 다시 시작하는 것입니다. 전체 논리. 실제로 'return 1'은 루프를 빠져 나올 수 있습니다. 편집 됨 ... – Mendes

+0

지금은 분명합니다. 비록 내가 개인적으로 여전히 완전히/깨끗하게 다시 시작하는 별도의 미니 프로그램을 갖는 접근법을 선호 할지라도 ... – Alex

2

올바른 질문을하기 위해 코딩에 대해 충분히 알지 못해서 잘못된 질문을하는 것처럼 들립니다.

누락 된 전화에서 처음 상태로 돌아가서 전체 호출/위치 시퀀스를 다시 시작하는 코드를 작성하는 방법을 묻는 것처럼 들립니다. 어떤 경우에는 state machine을 사용해야합니다. 그것이 무엇인지, 어떻게 쓰는지 찾아보십시오. 이것은 중요한 소프트웨어 개념이며 선생님이 직업에 능숙하다면 그것을 알아야합니다.

부수적으로 프로그램에서 모든 변수를 초기화하는 데 5 초가 걸리면 다시 시작할 때 5 초가 걸리게됩니다. 당신은 바로 가기를 할 수 없습니다. 그래서 그것은 당신이 을 가지고 있지 않다는 것을 분명히해야합니다.은 실제로 프로그램을 죽이고 다시 시작하기를 원합니다. 원하지 않는 행동을 정확하게 얻을 수 있기 때문입니다. 상태 시스템을 사용하면 시스템이 방금 켜졌을 때의 초기 기동을위한 초기화 상태 하나와 웜 재시작의 두 번째 초기화 상태를 가질 수 있습니다.

아, 6 개의 스레드가 그리 많지 않습니다! :)

+0

물론 많은 것을 배우고 향상시켜야합니다. "전체"호출/위치 시퀀스를 다시 시작하고 싶지 않습니다. 전체 응용 프로그램, 7 개 파일, 센서 바이어스를 다시 시작하고 싶습니다. 필요한 프로그램이므로 프로그램을 다시 시작하고 싶습니다. 웜 리 스타트 (warm restart)를하면 코드와 노력이 너무 많이 들지만 아무 것도 얻지는 못한다. 코드를 복잡하게 만든다. –

+0

파일을 닫은 다음 다시 열고 변수를 다시 초기화 하시겠습니까? 그런 다음 부재 중 통화 후 파일을 닫습니다. 루프를 사용하여 다시 돌아와서 초기화 작업을 다시 수행하십시오. 나는 무례하게하려고하지는 않지만, 애플리케이션을 재시작하는 것이 단순한 루프에 대한 합리적인 대안이 될 수있는 상황은 없다. 이것이 유니 프로젝트 인 경우 기술 능력이 부족하다는 것을 증명하면 *** 등급이 낮아질 것입니다. 나는 무례하게 굴지 않으려 고, 나는 너에게 좋은 성적을주는 방향으로 너를 가르치려고 노력하고있어. :) – Graham