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

Jul*_*nga 48 c++ application-restart

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

我不知道是否有任何方法可以实现这一目标或是否可行.

Sin*_*all 62

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

  • 他们不互相打电话; 调用者基本上是一个调用第二个循环的循环,等待它退出,然后再次调用它."真正的"程序对调用者一无所知; 它只是退出. (7认同)
  • 为什么不启动程序的另一个实例,可能指定一个标志,表明它是重启? (4认同)
  • 并且工人可以通过其退出代码指示是否想要由看门狗重新启动. (3认同)

krz*_*zaq 46

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

int main()
{
    while(!i_want_to_exit_now) {
        // code
    }
}
Run Code Online (Sandbox Code Playgroud)

或者,如果要实际重新启动程序,请从线束运行它:

program "$@"
while [ $? -e 42 ]; do
    program "$@"
done
Run Code Online (Sandbox Code Playgroud)

42返回码在哪里,意思是"请重启,请".

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

void restart() {
    std::exit(42);
}
Run Code Online (Sandbox Code Playgroud)

  • @HumamHelfawi如果程序有内存泄漏,无论如何它们都应该被修复,无论它是否在循环中运行.使用相同的逻辑,你可以说第一种方法并不好,因为如果程序有UB,它会有几次UB ...... (16认同)
  • 这是最具体的答案.应将_标记为answer_. (4认同)
  • 如果程序编写得不好,第一种解决方案将无法正常工作.例如,如果它包含内存泄漏,则只需通过循环就不会释放它.但是,您提供的其他解决方案甚至可以处理这些问题. (3认同)
  • @ tobi303不,不好.然而,"重新启动程序"这个短语意味着"清理所有垃圾"或换句话说:"清除所有垃圾并开始新鲜".所以我认为清洁任何泄漏都是其中的一部分......无论如何,我是与你没有人留下泄漏并使用重启方法来解决它.我只是觉得值得一提 (3认同)
  • @HumamHelfawi:实际上,我已经看到了分析不试图释放内存的图像的程序.它们是单拍程序,可以在下一个图像外部重新运行.(我经常不担心在小型测试程序中释放内存.) (3认同)

cat*_*cat 15

在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;
}
Run Code Online (Sandbox Code Playgroud)

例:

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

7 | $
Run Code Online (Sandbox Code Playgroud)

(7是返回码).

它既不是recurses也不是显式循环 - 相反,它只是调用自身,用自己的新版本替换自己的内存空间.

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

在自我更新二进制文件的情况下,由于整个二进制文件(至少在Unix上喜欢,我不知道关于Windows)将在运行时复制到内存中,如果文件在execve(argv[0], ...调用之前在磁盘上发生变化,将运行在磁盘上找到的新二进制文件,而不是旧的二进制文件.

正如@CarstenS和@bishop在评论中指出的那样,由于Unix的独特设计方式,打开的文件描述符保持在fork/ exec,因此为了避免在调用时泄露打开的文件描述符execve,你应该之前关闭它们execve或者打开它们e,FD_CLOEXEC/ O_CLOEXEC在首位-更多信息可以在发现丹沃尔什的博客.

  • 那些可能获得的资源呢? (3认同)
  • 哦,我认为@bishop对开放文件描述符是正确的 - 那些首先需要关闭,或者首先用`FD_CLOEXEC`打开.当有人谈论C/C++泄漏时,文件描述符不是我首先想到的:) (2认同)
  • "strace"这个版本可能是有益的.我写了一个终止:`int main(int argc,char**argv){(void)argc; printf("arg:%s \n",argv [1]); int count = atoi(argv [1]); if(count> 0){char buf [20]; sprintf(buf,"%d",count-1); argv [1] = buf; execv(argv [0],argv); } return count; }`.你可以每次都看到启动(加载`libc`等). (2认同)

Blu*_*eft 13

这是一个特定于操作系统的问题.在Windows中,您可以使用Application Restart APIMFC Restart Manager.在Linux中你可以做一个exec()

但是大多数时候都有更好的解决方案.如其他答案所示,您最好使用循环.


Lig*_*ica 9

这听起来像是错误的方法,就像你的所有状态都是全局的一样,所以你重置所有内容的唯一明确方法(除了为每个变量手动分配"默认"值)是重启整个程序.

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

不要对抗C++; 用它!


Arn*_*rah 6

你可能需要一个循环:

int main()
{
    while (true)
    {
        //.... Program....
    }
}
Run Code Online (Sandbox Code Playgroud)

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