17

我有一个广泛的问题:

假设我有一个 C++ 程序,我开始在后台的一个文件上运行它,并使用一些可以在内部设置的配置。在它运行时,我更改了这些内部配置,编译它并开始在另一个文件上运行它。

这会影响已经在后台运行的前一个实例吗?还是因为它已经启动并运行它不会?对此的任何想法表示赞赏。

4

3 回答 3

20

修改正在运行的可执行文件是不安全的。根据覆盖内存映射的可执行文件时会发生什么?

在 Linux 下,如果在运行时替换可执行文件,结果是不可预测的,并且可能会崩溃。

如果您删除该文件并编译程序的新版本,那么将会发生什么是非常明确的。已经运行的实例将使用先前的代码,并且该代码将由操作系统保存在内存中,直到程序终止。任何新实例都将使用新代码。

总结:您应该确保您的构建系统在重新编译之前删除旧的可执行文件,只要这是真的,那么重新编译将在您重新运行程序之前生效,否则行为未定义(阅读 SIGSEGV)。

各种附录:

JamesKanze 正确地指出,链接器本身可能会在写入其输出之前删除文件,如果是这种情况,那么它将总是表现得好像您在重新编译之前自己删除了文件(理智的场景)。从 binutils cvs 头查看bfd /cache.c :

/* Create the file.

   Some operating systems won't let us overwrite a running
   binary.  For them, we want to unlink the file first.

   However, gcc 2.95 will create temporary files using
   O_EXCL and tight permissions to prevent other users from
   substituting other .o files during the compilation.  gcc
   will then tell the assembler to use the newly created
   file as an output file.  If we unlink the file here, we
   open a brief window when another user could still
   substitute a file.

   So we unlink the output file if and only if it has
   non-zero size.  */

所以至少对于 GNU LD,这是可以保证的。然而,这不一定扩展到其他链接器。

于 2012-08-20T16:03:16.243 回答
6

可能/将会发生什么取决于操作系统,但一般来说,您的旧程序永远不会开始使用新代码运行。我说它取决于操作系统,因为在 Windows 上我相信该文件将被锁定并且您根本无法覆盖它,而在 Linux 上,您将本质上取消链接旧文件,但程序仍将使用该旧版本,并且您的新版本在技术上将是一个不同的文件。

现在这里有一个警告。如果您有动态库或其他动态代码资源,那么您可能会获得新版本。在任何情况下,您都按需加载库,您加载的版本将是加载时存在的版本。在大多数情况下,所有库都在程序开始时直接加载。然而,它们不是的一种常见情况是插件架构,它们根据需要加载。

于 2012-08-20T15:58:11.377 回答
4

不,它不会影响原始运行的实例——它已经加载到内存中并且不会被更改。

于 2012-08-20T15:55:25.953 回答