这个问题有几个方面:
a和b会打印出什么?我能想到可能会发生的几件事情:
Linker error: x declared extern but never defined.
由于a和b可能还没有被编译成可执行文件,因此不会打印任何内容。当然,您需要链接lib.so、lib.a或一个导入库lib.lib,以将可执行文件暴露给x的可链接定义,否则什么也不起作用(大多数情况下是这样,如果努力尝试可能会更复杂)。
Each process gets it's own x, including lib. (b.c is always 0, a.c counts down, lib counts up)
在您的场景中,lib不是一个进程,而是一个共享库。这个共享库在每个进程空间中被单独加载和链接,只要有东西以动态加载器(ld-linux.so,在Windows上为ntdll.dll)理解的方式引用它。每个进程在其地址空间中观察到已加载库的副本,并且库本身看到相同的副本,因此运行a应该永远打印0后跟1。 p()被运行并测试,x被打印,x被递减回0。b也将永远打印0后跟1。p()被运行并测试,x被打印,x被设置为0。请注意,p()打印x++,因此增量是在捕获printf参数的值之后发生的。包含a和b的程序所引用的x变量对于每次运行a或b都是特定的。这通常是通过在操作系统级别映射实际可加载库的页面到内存中并将它们设置为“写时复制”来完成的,其中主机进程尝试更改会导致操作系统首先分配新页面并在第一次复制旧内容时进行复制。结果是,未修改的已加载库部分占用的实际内存较少。
Each process gets it's own x to share with lib. (a.c and b.c are always 1, lib is always 0)
Lib不是一个独立的进程。在执行p()时,它所看到的x与a链接的x相同。
All processes share the same x, including lib. (a.c, b.c and lib return random values)
通常不是这种情况(也请参见下文)。
All processes share the same x, including lib, until someone other than lib writes to it, then that process gets it's own version of x, not shared with lib (Read this online somewhere). (lib always increments, b.c always prints 0, a.c counts down)
一些旧的运行时系统不支持分离地址空间,例如AmigaDOS。但你很少会遇到这种情况。
What typically happens? Are there any inconsistencies between compilers/platforms we should know about? Can we force one behaviour (I am thinking __declspec(dllexport), compiler flags, etc.)?
在绝大多数情况下,每个进程与在该进程中加载的给定库的一个实例共享外部变量。除非您采取特定措施,否则这是预期的。
在评论中,还有一些其他问题:
Can windows dlls (or others) export non-function data.
是的,当构建导入库时,请在.def文件中使用DATA限定符。 对于其他函数,与导出函数无异。 但是,您将收到指向目标变量的指针,而不是绑定到占用空间。
Asterisk, see below?
在Windows上,section拥有一个SHARED属性,会导致加载器在使用DLL的每个进程中分配相同的页面。这不是默认设置,您需要采用平台特定的pragma方式来实现它。有很多原因不要使用这个功能。
大多数时候,当dll想要在许多进程中加载的副本中共享状态时,它使用主机系统的共享内存API(通常为CreateFileMapping或mmap)。这样可以实现灵活性(例如,所有进程可以共享一个x的版本,与具有另一个x副本的所有b进程分开)。请注意,使用SHARED可能会导致运行a崩溃b,并且另一个长时间运行的用户c加载可能会使a或b无法重新启动,直到重启计算机。
lib
导出的extern int x
,则链接器会报错,这可能意味着使用该链接器时库无法导出变量。至于您评论中的其余内容,如果我理解正确:例如写入到extern int x
将不可见于其他进程,但对于lib
,只有在调用该进程时才能看到(就像情况3一样,除了最初所有进程共享相同的x
)。是这样吗?还是您(通过“写入时复制”)的意思是当您写入一个变量时,它将创建一个lib
不使用的新变量? - yyny