C++ 是否可以从程序内部重新启动程序?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/40022586/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 15:20:15  来源:igfitidea点击:

Is it possible to restart a program from inside a program?

c++application-restart

提问by Julen Uranga

I am developing a C++ program and it would be useful to use some function, script or something that makes the program restart. It's a big program so restarting all the variables manually will take me long time...

我正在开发一个 C++ 程序,使用一些函数、脚本或使程序重新启动的东西会很有用。这是一个大程序,所以手动重新启动所有变量将花费我很长时间......

I do not know if there is any way to achieve this or if it is possible.

我不知道是否有任何方法可以实现这一目标,或者是否有可能。

回答by SingerOfTheFall

If you really need to restart the whole program (i.e. to "close" and "open" again), the "proper" way would be to have a separate program with the sole purpose of restarting your main one. AFAIK a lot of applications with auto-update feature work this way. So when you need to restart your main program, you simply call the "restarter" one, and exit.

如果您真的需要重新启动整个程序(即再次“关闭”和“打开”),“正确”的方法是拥有一个单独的程序,其唯一目的是重新启动您的主程序。AFAIK 许多具有自动更新功能的应用程序都以这种方式工作。因此,当您需要重新启动主程序时,只需调用“重新启动器”,然后退出即可。

回答by krzaq

You can use a loop in your mainfunction:

您可以在main函数中使用循环:

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

Or, if you want to actually restart the program, run it from a harness:

或者,如果您想真正重新启动程序,请从线束中运行它:

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

where 42is a return code meaning "restart, please".

哪里42是返回码,意思是“请重启”。

Then inside the program your restartfunction would look like this:

然后在程序内部,您的restart函数将如下所示:

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

回答by cat

On Unicies, or anywhere else you have execveand it works like the man page specifies, you can just...kill me for using atoi, because it's generally awful, except for this sort of case.

在 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;
}

Example:

例子:

$ ./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 was the return code).

(7 是返回码)。

It neither recurses nor explicitly loops -- instead, it just calls itself, replacing its own memory space with a new version of itself.

它既不递归也不显式循环——相反,它只是调用自己,用自己的新版本替换自己的内存空间。

In this way, the stack will never overflow, though all previous variables will be redeclared, just like with any reinvocation -- the getcharcall prevents 100% CPU utilisation.

通过这种方式,堆栈永远不会溢出,尽管所有先前的变量都将被重新声明,就像任何重新getchar调用一样——该调用阻止了 100% 的 CPU 使用。

In the case of a self-updating binary, since the entire binary (at least, on Unix-likes, I don't know about Windows) will be copied into memory at runtime, then if the file changes on disk before the execve(argv[0], ...call, the new binary found on disk, not the same old one, will be run instead.

在自更新二进制文件的情况下,由于整个二进制文件(至少,在类 Unix 上,我不了解 Windows)将在运行时复制到内存中,那么如果文件在execve(argv[0], ...调用前在磁盘上发生更改,在磁盘上找到的新二进制文件,而不是旧的二进制文件,将改为运行。

As @CarstenS and @bishop point out in the comments, due to the unique way in which Unix was designed, open file descriptors are kept across fork/exec, and as a result in order to avoid leaking open file descriptors across calls to execve, you should either close them before execveor open them with e, FD_CLOEXEC/ O_CLOEXECin the first place -- more information can be found on Dan Walsh's blog.

正如@CarstenS 和@bishop 在评论中指出的那样,由于 Unix 的独特设计方式,打开的文件描述符保存在fork/ 中exec,因此为了避免在调用之间泄漏打开的文件描述符execve,您应该要么首先关闭它们execve或使用e, FD_CLOEXEC/打开它们O_CLOEXEC——更多信息可以在Dan Walsh 的博客上找到。

回答by BlueRaja - Danny Pflughoeft

This is a very OS-specific question. In Windows you can use the Application Restart APIor MFC Restart Manager. In Linux you could do an exec()

这是一个非常针对操作系统的问题。在 Windows 中,您可以使用Application Restart APIMFC Restart Manager。在 Linux 中,你可以做一个exec()

However most of the time there is a better solution. You're likely better off using a loop, as suggested in other answers.

然而,大多数时候有更好的解决方案。正如其他答案中所建议的那样,您最好使用循环。

回答by Lightness Races in Orbit

This sounds like the wrong approach, like all your state is global and so the only clear-cut method you have of resetting everything (other than to manually assign "default" values to each variable) is to restart the whole program.

这听起来像是错误的方法,因为您的所有状态都是全局的,因此您重置所有内容的唯一明确方法(除了手动为每个变量分配“默认”值)是重新启动整个程序。

Instead, your state should be held in objects (of class type, or whatever). You are then free to create and destroy these objects whenever you like. Each new object has a fresh state with "default" values.

相反,您的状态应该保存在对象(类类型或其他类型)中。然后,您可以随时随意创建和销毁这些对象。每个新对象都有一个带有“默认”值的新状态。

Don't fight C++; use it!

不要和 C++ 打架;用它!

回答by Arnav Borborah

You probably need a loop:

你可能需要一个循环:

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

Every time you need to restart, call continue;within the loop, and to end your program, use break;.

每次需要重新启动时,请continue;在循环内调用并结束程序,请使用break;.

回答by Mendes

When I develop realtime systems my approach is normally a "derived main()" where I write all code called from a real main(), something like:

当我开发实时系统时,我的方法通常是“派生 main()”,其中我编写了从真正的 main() 调用的所有代码,例如:

The main.cpp program:

main.cpp 程序:

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

The programmain.cpp, where all code is written:

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;
}

In that way, every time we decide to exit the program the program will be restarted.

这样,每次我们决定退出程序时,程序都会重新启动。

Detail: all variables, globals and logic must be written inside programMain()- nothing inside "main()"except the restart control.

细节:所有变量、全局变量和逻辑都必须写在里面programMain()——"main()"除了重启控制之外什么都没有。

This approach works in both Linux and Windows systems.

这种方法适用于 Linux 和 Windows 系统。

回答by Graham

It sounds to me like you're asking the wrong question because you don't know enough about coding to ask the right question.

在我看来,您问错了问题,因为您对编码的了解不足以提出正确的问题。

What it sounds like you're asking for is how to write some code where, on a missed call, it loops back round to the initial state and restarts the whole call/location sequence. In which case you need to use a state machine. Look up what that is, and how to write one. This is a key software concept, and you should know it if your teachers were any good at their job.

听起来您要求的是如何编写一些代码,在未接来电时,它会循环回到初始状态并重新启动整个呼叫/定位序列。在这种情况下,您需要使用状态机。看看那是什么,以及如何写一个。这是一个关键的软件概念,如果您的老师擅长他们的工作,您应该知道这一点。

As a side note, if your program takes 5s to initialise all your variables, it's still going to take 5s when you restart it. You can't shortcut that. So from that it should be clear that you don'tactually want to kill and restart your program, because then you'll get exactly the behaviour you don't want. With a state machine you could have one initialisation state for cold startup where the system has only just been turned on, and a second initialisation state for a warm restart.

附带说明一下,如果您的程序需要 5 秒来初始化所有变量,那么重新启动它时仍然需要 5 秒。你不能走捷径。因此,从它应该是明确的,你真正想杀死并重新启动程序,因为这样你会得到正是你不想要的行为。使用状态机,您可以有一个用于冷启动的初始化状态,其中系统刚刚打开,而第二个初始化状态用于热重启。

Oh, and 6 threads is not very many! :)

哦,6 个线程不是很多!:)

回答by MatthewRock

Depending on what you mean by "restarting" the program, I can see few simple solutions.

根据“重新启动”程序的含义,我可以看到几个简单的解决方案。

One is to embed your whole program in some "Program" class, that essentially provides some loop that has your proper program. When you need to restart the program, you call static public method "Restart" that starts the loop again.

一种是将您的整个程序嵌入到某个“程序”类中,这实质上提供了一些具有您正确程序的循环。当您需要重新启动程序时,您可以调用静态公共方法“Restart”来再次启动循环。

You could also try to make system-specific call that would start your program again, and exit. As suggested in other answer, you could create a wrapper program for this sole purpose(and check return code to know whether to quit or restart).

您还可以尝试进行特定于系统的调用,以再次启动您的程序,然后退出。正如其他答案中所建议的那样,您可以为此单独创建一个包装程序(并检查返回代码以了解是退出还是重新启动)。

The other simple option is to use goto. I know that people will hate me for even mentioning it, but let's face it: we want to make simple program, not use beautiful boilerplate. Goto going back guarantees destruction, so you could create a program with a label in the beginning, and some function "Restart" that just goes back to the beginning.

另一个简单的选择是使用goto. 我知道人们会因为提到它而讨厌我,但让我们面对现实:我们想要制作简单的程序,而不是使用漂亮的样板。Goto 返回保证销毁,因此您可以创建一个在开头带有标签的程序,以及一些可以返回到开头的“重新启动”函数。

Whatever option you choose, document it well, so others(or you in the future) will use one WTF less.

无论您选择什么选项,都要做好记录,这样其他人(或将来的您)将少使用一个 WTF。

PS. As mentioned by alain, gotowill not destroy global nor static objects, same would go for enclosing class. Therefore any approach that does not include starting new program in place of the current one should either refrain from using global/static variables, or take proper actions to re-set them(although that might be tedious, as with addition of each static/global, you need to modify the restart routine).

附注。正如alain所提到的,goto不会破坏全局或静态对象,封闭类也是如此。因此,任何不包括启动新程序代替当前程序的方法都应该避免使用全局/静态变量,或者采取适当的措施来重新设置它们(尽管这可能很乏味,因为添加每个静态/全局变量) ,需要修改重启例程)。