如果在另一个实例已经运行的情况下编译程序会发生什么?

时间:2012-04-18 06:13:00

标签: c++

$ g++ program.cpp

$ ./a.out &

(program.cpp已修改。)

$ g++ program.cpp

如果覆盖可执行文件,运行过程如何仍能产生准确的结果?

4 个答案:

答案 0 :(得分:7)

因为旧文件仍然存在。目录条目将指向一个新文件,但只要它保持打开状态,旧文件就会存在。关闭后,它将最终被删除。也就是说,在Unix上。在Windows上,您可能无法执行此操作,因为文件已打开且无法覆盖。

答案 1 :(得分:5)

这实际上取决于ld(由g++调用)如何创建 新的可执行文件。如果只是open(带有正确的标志) 如果文件不存在则创建,那么会发生什么 运行过程取决于分页,但很有可能发生崩溃。 如果它首先执行unlink,则在创建新文件之前,正在运行 进程将继续使用旧图像,该图像将仅被释放 当过程结束。

传统上,最初的Unix连接器使用了第一种策略 具有保持现有访问权限的优点 可执行文件。然而,这是在虚拟内存时代之前的时候 在exec的调用中,一次性加载了一个可执行文件 之后发生的文件无关紧要。今天,如果我是 写一个链接器,我会使用第二个,但首先要读取模式 原始文件,并使用相同的模式创建新文件。

您可以通过创建来轻松查看正在使用的策略 可执行文件,然后更改模式,然后对其执行ls -il 重新编译,再次执行ls -il。如果inode编号已更改, 链接器在打开输出之前正在执行unlink。如果是的话 模式已更改(返回到您环境中的默认值), 链接器在执行之前无法读取原始模式 unlink

对于Linux下的g ++,无论是inode编号还是模式 更改。 (我会考虑模式改变了一个错误的事实。)IIRC,on 另一方面,Solaris下的ld没有删除文件 - 我没有删除 回想起上面的测试,但我确实对程序有模糊的记忆 当我们重新编译他们正在使用的DLL之一时崩溃。

最后,FWIW,为什么删除文件不会导致应用程序崩溃: Unix下的文件(由inode表示)是引用计数,并且是 当引用计数变为0时自动删除。(非常多 例如shared_ptr。)每个目录条目都有一个引用计数 指向文件(每个硬链接),以及每个打开的文件描述符 指的是文件。在Unix下“删除”文件实际上并不存在 触摸该文件,它只是删除指向它的目录条目 (减少使用计数,这可能导致文件正在使用 删除)。加载的可执行文件包含一个打开的文件描述符 可执行文件及其加载的所有.so,计为a 引用该文件,因此删除指向的最后一个目录条目 它仍将使引用计数大于0。

编辑:我可能会补充说,取消链接也会破坏硬链接(这会 仍然指向旧版本)。这可能不是问题 今天,因为每个人都只使用软链接(这是一个引用 文件名,而不是文件本身),但我记得回来了 早期,在软链接存在之前,我们努力避免破坏 链接:在我编辑的编辑器中,我们将输出写成了一个全新的 文件,然后将其移动到原始文件(如果inode计数 是1),或复制它(如果inode计数大于1;即如果 还有其他硬链接到我们不知道的文件)。

答案 2 :(得分:1)

没有

较早的./a.out进程会将a.out的内容映射到内存中(在各个部分中,您可以在/proc/$PID/smaps中看到它们。)

后面的g++ program.cpp 取消链接现有的a.out文件,并创建一个具有相同名称的新文件。早期的可执行文件仍然映射到内存中的早期文件未被修改。

答案 3 :(得分:0)

在Unix上,一旦旧文件关闭,它将被删除,而在Windows上,它会抛出错误,说无法在所需位置复制可执行文件