我有一个广泛的问题:
假设我有一个C ++程序,我开始在后台运行一个文件,其中一些配置可以在内部设置。在它运行时,我更改了这些内部配置,编译它并开始在另一个文件上运行它。
这是否会影响之前已在后台运行的实例?或者因为它已经启动并运行它不会?对此有任何想法表示赞赏。
答案 0 :(得分:19)
修改正在运行的可执行文件是不安全的。根据{{3}}
在Linux下,如果在运行时替换可执行文件,则 结果是不可预测的,可能会崩溃。
如果您删除该文件并编译该程序的新版本,那么将会定义的内容非常明确。已经运行的实例将使用前面的代码,操作系统将在内存中保存,直到程序终止。任何新实例都将使用新代码。
摘要:您应该确保您的构建系统在重新编译之前删除旧的可执行文件,并且只要这是真的,那么重新编译在重新运行程序之前不会生效,否则行为是未定义的(读取SIGSEGV)。
各种附录:
JamesKanze正确地指出链接器本身可能会在写入其输出之前删除该文件,如果是这种情况,那么它将始终表现得就像您在重新编译之前自己删除了文件一样(理智的场景)。从binutils cvs head看What happens when you overwrite a memory-mapped executable?:
/* 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来说,这可以保证很好。然而,这并不一定延伸到其他连接器。
答案 1 :(得分:6)
可能/将要发生什么取决于操作系统,但一般来说,旧程序永远不会开始使用新代码运行。我说这是依赖操作系统的,因为在Windows上我认为文件将被锁定而你根本无法覆盖它,而在Linux上,你必须取消链接旧文件,但程序仍将使用旧版本,而你的新版本在技术上将是一个不同的文件。
现在有一个警告。如果您有动态库或其他动态代码资源,那么您可能会获得新版本。在任何情况下,您根据需要加载库,您加载的版本将是加载时存在的版本。在大多数情况下,所有库都在程序开始时直接加载。然而,它们不是插件架构的一种常见情况是根据需要加载它们。
答案 2 :(得分:4)
不,它不会影响原来正在运行的实例 - 它已经加载到内存中而且不会被更改。