是否可以从程序内部重新启动程序?
Is it possible to restart a program from inside a program?
我正在开发一个 C++ 程序,使用一些函数、脚本或使程序重新启动的东西会很有用。这是一个大程序,因此手动重新启动所有变量将花费我很长时间...
不知道有没有什么办法可以实现。
您可能需要一个循环:
int main()
{
while (true)
{
//.... Program....
}
}
每次需要重新启动时,在循环中调用 continue;
,要结束程序,请使用 break;
。
如果你真的需要重新启动整个程序(即再次 "close" 和 "open"),"proper" 方法是有一个单独的程序,其唯一目的是重新启动你的主要的。据我所知,许多具有自动更新功能的应用程序都是这样工作的。所以当你需要重新启动你的主程序时,你只需调用 "restarter" 一个,然后退出。
您可以在 main
函数中使用循环:
int main()
{
while(!i_want_to_exit_now) {
// code
}
}
或者,如果您想实际重新启动程序,运行 它来自线束:
program "$@"
while [ $? -e 42 ]; do
program "$@"
done
其中 42
是一个 return 代码,意思是 "restart, please"。
然后在程序内部,您的 restart
函数将如下所示:
void restart() {
std::exit(42);
}
这是一个非常 OS 的问题。在Windows中你可以使用Application Restart API or MFC Restart Manager。在 Linux 你可以做一个 exec()
然而,大多数时候都有更好的解决方案。正如其他答案中所建议的那样,您最好使用循环。
在 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 是 return 代码)。
它既不递归也不显式循环——相反,它只是调用自己,用自己的新版本替换自己的内存 space。
通过这种方式,堆栈将永远不会溢出,尽管所有先前的变量都将被重新声明,就像任何重新调用一样——getchar
调用可防止 100% CPU 使用。
在自更新二进制文件的情况下,因为整个二进制文件(至少,在 Unix-likes 上,我不知道 Windows)将被复制到内存中 运行time,那么如果文件在 execve(argv[0], ...
调用之前在磁盘上发生更改,则在磁盘上找到的新二进制文件(与旧二进制文件不同)将改为 运行。
正如@CarstenS 和@bishop 在评论中指出的那样,由于 Unix 的独特设计方式,打开的文件描述符在 fork
/exec
中保留,因此为了避免在调用 execve
时泄漏打开的文件描述符,您应该在 execve
之前关闭它们,或者在 e
、FD_CLOEXEC
/ O_CLOEXEC
中打开它们第一名——更多信息可以在 Dan Walsh's blog.
上找到
根据您所说的 "restarting" 程序的含义,我可以看到几个简单的解决方案。
一种是将您的整个程序嵌入到某些 "Program" class 中,这实质上提供了一些具有您的正确程序的循环。当您需要重新启动程序时,您调用静态 public 方法 "Restart" 再次启动循环。
您也可以尝试进行系统特定的调用,这将再次启动您的程序,然后退出。
正如其他答案中所建议的,您可以为此唯一目的创建一个包装程序(并检查 return 代码以了解是退出还是重新启动)。
另一个简单的选项是使用 goto
。我知道人们会因为我提到它而讨厌我,但让我们面对现实吧:我们想要制作简单的程序,而不是使用漂亮的样板。 Goto going back guarantees destruction,所以你可以创建一个程序,在开头有一个标签,而一些函数 "Restart" 只是回到开头。
无论您选择什么选项,请将其记录下来,这样其他人(或将来的您)就会少用一个 WTF。
PS。正如 所提到的,goto
不会破坏全局或静态对象,封闭 class 也是如此。因此,任何不包括启动新程序来代替当前程序的方法都应该避免使用 global/static 变量,或者采取适当的措施来重新设置它们(尽管这可能很乏味,就像添加每个 static/global,需要修改重启例程)。
这听起来像是错误的方法,就像你所有的状态都是全局的,所以你唯一可以重置所有内容的明确方法(除了手动为每个变量分配 "default" 值)是重新启动整个程序。
相反,您的状态应该保存在对象(class 类型或其他类型)中。然后您可以随时自由地创建和销毁这些对象。每个新对象都有一个具有 "default" 个值的新状态。
不要对抗C++;使用它!
当我开发实时系统时,我的方法通常是 "derived 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 系统。
在我看来你问错了问题,因为你对编码的了解还不够多,无法提出正确的问题。
听起来您要问的是如何编写一些代码,在未接来电时,它会循环回到初始状态并重新启动整个 call/location 序列。在这种情况下,您需要使用 state machine。查看那是什么,以及如何编写。这是一个关键的软件概念,如果您的老师擅长他们的工作,您应该知道这一点。
附带说明一下,如果您的程序需要 5 秒来初始化所有变量,那么当您重新启动它时,它仍然需要 5 秒。你不能走捷径。所以从那应该清楚你不实际上想要杀死并重新启动你的程序,因为那样你就会得到确切的行为你不想要。使用状态机,您可以有一个系统刚刚打开的冷启动初始化状态,以及热重启的第二个初始化状态。
哦,6个线程也不是很多! :)
我正在开发一个 C++ 程序,使用一些函数、脚本或使程序重新启动的东西会很有用。这是一个大程序,因此手动重新启动所有变量将花费我很长时间...
不知道有没有什么办法可以实现。
您可能需要一个循环:
int main()
{
while (true)
{
//.... Program....
}
}
每次需要重新启动时,在循环中调用 continue;
,要结束程序,请使用 break;
。
如果你真的需要重新启动整个程序(即再次 "close" 和 "open"),"proper" 方法是有一个单独的程序,其唯一目的是重新启动你的主要的。据我所知,许多具有自动更新功能的应用程序都是这样工作的。所以当你需要重新启动你的主程序时,你只需调用 "restarter" 一个,然后退出。
您可以在 main
函数中使用循环:
int main()
{
while(!i_want_to_exit_now) {
// code
}
}
或者,如果您想实际重新启动程序,运行 它来自线束:
program "$@"
while [ $? -e 42 ]; do
program "$@"
done
其中 42
是一个 return 代码,意思是 "restart, please"。
然后在程序内部,您的 restart
函数将如下所示:
void restart() {
std::exit(42);
}
这是一个非常 OS 的问题。在Windows中你可以使用Application Restart API or MFC Restart Manager。在 Linux 你可以做一个 exec()
然而,大多数时候都有更好的解决方案。正如其他答案中所建议的那样,您最好使用循环。
在 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 是 return 代码)。
它既不递归也不显式循环——相反,它只是调用自己,用自己的新版本替换自己的内存 space。
通过这种方式,堆栈将永远不会溢出,尽管所有先前的变量都将被重新声明,就像任何重新调用一样——getchar
调用可防止 100% CPU 使用。
在自更新二进制文件的情况下,因为整个二进制文件(至少,在 Unix-likes 上,我不知道 Windows)将被复制到内存中 运行time,那么如果文件在 execve(argv[0], ...
调用之前在磁盘上发生更改,则在磁盘上找到的新二进制文件(与旧二进制文件不同)将改为 运行。
正如@CarstenS 和@bishop 在评论中指出的那样,由于 Unix 的独特设计方式,打开的文件描述符在 fork
/exec
中保留,因此为了避免在调用 execve
时泄漏打开的文件描述符,您应该在 execve
之前关闭它们,或者在 e
、FD_CLOEXEC
/ O_CLOEXEC
中打开它们第一名——更多信息可以在 Dan Walsh's blog.
根据您所说的 "restarting" 程序的含义,我可以看到几个简单的解决方案。
一种是将您的整个程序嵌入到某些 "Program" class 中,这实质上提供了一些具有您的正确程序的循环。当您需要重新启动程序时,您调用静态 public 方法 "Restart" 再次启动循环。
您也可以尝试进行系统特定的调用,这将再次启动您的程序,然后退出。 正如其他答案中所建议的,您可以为此唯一目的创建一个包装程序(并检查 return 代码以了解是退出还是重新启动)。
另一个简单的选项是使用 goto
。我知道人们会因为我提到它而讨厌我,但让我们面对现实吧:我们想要制作简单的程序,而不是使用漂亮的样板。 Goto going back guarantees destruction,所以你可以创建一个程序,在开头有一个标签,而一些函数 "Restart" 只是回到开头。
无论您选择什么选项,请将其记录下来,这样其他人(或将来的您)就会少用一个 WTF。
PS。正如 goto
不会破坏全局或静态对象,封闭 class 也是如此。因此,任何不包括启动新程序来代替当前程序的方法都应该避免使用 global/static 变量,或者采取适当的措施来重新设置它们(尽管这可能很乏味,就像添加每个 static/global,需要修改重启例程)。
这听起来像是错误的方法,就像你所有的状态都是全局的,所以你唯一可以重置所有内容的明确方法(除了手动为每个变量分配 "default" 值)是重新启动整个程序。
相反,您的状态应该保存在对象(class 类型或其他类型)中。然后您可以随时自由地创建和销毁这些对象。每个新对象都有一个具有 "default" 个值的新状态。
不要对抗C++;使用它!
当我开发实时系统时,我的方法通常是 "derived 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 系统。
在我看来你问错了问题,因为你对编码的了解还不够多,无法提出正确的问题。
听起来您要问的是如何编写一些代码,在未接来电时,它会循环回到初始状态并重新启动整个 call/location 序列。在这种情况下,您需要使用 state machine。查看那是什么,以及如何编写。这是一个关键的软件概念,如果您的老师擅长他们的工作,您应该知道这一点。
附带说明一下,如果您的程序需要 5 秒来初始化所有变量,那么当您重新启动它时,它仍然需要 5 秒。你不能走捷径。所以从那应该清楚你不实际上想要杀死并重新启动你的程序,因为那样你就会得到确切的行为你不想要。使用状态机,您可以有一个系统刚刚打开的冷启动初始化状态,以及热重启的第二个初始化状态。
哦,6个线程也不是很多! :)