【问题标题】:Sharing static and global variables across instances of the same DLL在同一个 DLL 的实例之间共享静态和全局变量
【发布时间】:2015-11-03 15:46:58
【问题描述】:

首先,有一些类似的问题,但没有一个真正解决确切的问题:

https://social.msdn.microsoft.com/forums/vstudio/en-US/b7701ee5-c9fa-4693-8ae1-d59736360514/question-about-static-variables-in-dll

http://cboard.cprogramming.com/cplusplus-programming/101543-global-static-variable-class-delivered-dll.html

所以,这是我的问题:我正在开发一个 VST 插件,并且我有一个在 DLL 中定义和实现的类。加载了同一个 DLL 的多个实例,我想做的是维护一个“实例计数”,它监视类被构造的次数(这只发生一次,当按照 VST 标准加载 DLL 时。)

这样做的一种直接方法是创建一个类静态变量,我将其初始化为 0,并在构造函数中递增/在析构函数中递减。我确信我知道我的类何时被构造和销毁,但我不确定这个类静态变量是否将在我的 DLL 实例之间共享。

为了澄清,我多次加载同一个 DLL;在 DLL 中是一个类(仅在 DLL 代码中使用,而不向应用程序公开。)关于 DLL 中定义的数据的行为是否在 Windows 和 Unix 之间有所不同,有一些讨论,所以我想知道如果在 DLL 中做这种事情对于跨平台使用是安全的。

在 DLL 中定义的示例类,不会以任何方式向加载 DLL(或其他方式)的应用程序公开。

头文件

// Foo.h
# pragma once
class Foo {
    static int s_InstanceCount;
public:
    Foo();
    ~Foo();
};

现在是源文件

// Foo.cpp
#include "Foo.h"
int Foo::s_InstanceCount = 0;

Foo::Foo() {
    s_InstanceCount++;
}

Foo::~Foo() {
    s_InstanceCount--;
    if (s_InstanceCount == 0) {
        // Do something
    }
}

Foo 的构造函数仅在应用程序加载 DLL 时调用(即 Windows 上的 ::LoadLibrary),而析构函数仅在 DLL 被释放时调用(即 Windows 上的 ::FreeLibrary)。考虑到保证。 s_InstanceCount 会在对构造函数的调用之间共享吗?

编辑: 正如 Serge 在下面指出的那样,一个进程不能真正加载 DLL 两次。因此,当我的 DLL 被一个进程加载两次时,构建的 Foo 实例存在于加载进程使用的同一内存空间中。也许……

【问题讨论】:

  • 当然,instanceCount 应该是atomic
  • 对,实际上我有一个关键部分,但我想要一个简单的例子。
  • 不,实际上你需要atomic,而不是CRITICAL_SECTION,为此。 CRTICAL_SECTIONs 只能在一个进程内工作,不能跨进程。
  • 见 Serge 的评论。这是“重新加载”同一个 DLL 的同一个过程,这并不是真正的事情,所以当 DLL 被“重新加载”时,我实际上只是在访问相同的变量。所以真的我的问题措辞不佳,因为进程不可能重新加载 DLL。但是,如果在同一个 DLL 上进行多个 ::LoadLibrary 调用,那么在该 DLL 中访问的变量将在类实例之间共享(我认为。)
  • 你仍然应该使用atomic

标签: c++ windows unix dll static


【解决方案1】:

DLL 只是在调用它的进程的地址空间中运行的共享代码。每个进程都有自己的 DLL 中定义的全局/静态变量的副本。

This article 向您解释了这一点。但它也提供了一个很好的解决方法,可以使用file mapping 在多个进程之间共享数据。这应该可以帮助您解决问题。

编辑:显然还有另一种解决方案,创建一个共享数据段(即告诉链接器共享一些数据,就像它对代码所做的那样)。这里microsoft docproof of concept on codeproject。我从未使用过它,因此它是否也适用于静态类成员还有待测试。

【讨论】:

  • 谢谢!我需要更多字符。
  • PS:与此同时,我已经尝试了共享分段方法。虽然我可以让它与全局或静态变量一起工作,但我无法设法共享静态类成员变量。
  • 共享数据段是一项遗留技术,应避免使用,因为它们are insecure
  • @HarryJohnston 很有趣。另一个限制似乎是只使用简单数据,因为动态对象必然会在共享段之外分配内存,并通过指向非共享内存导致未定义的行为。
【解决方案2】:

不,您的示例中的s_InstanceCount 将是每个 DLL 实例的私有。此外,如果不调整 DLL 的文件名,您通常无法在同一进程中多次加载它,如下所述:Load the same dll multiple times。 如果在您的情况下 DLL 实例位于不同的进程中,那么您需要进程间通信,例如通过shared memory

【讨论】:

  • 嗯。所以我想真正发生的是每次“重新加载”DLL时什么都没有发生;同一个 DLL 中的相同变量正在被同一个进程访问。这就是我想要的。谢谢!
  • 你怎么知道DLL被“重新加载”了?我无法想象你所描述的会发生什么:当一个DLL被卸载时,属于它的变量应该被销毁,所以DLL的新加载应该得到新的变量。
  • 如果在卸载之前加载了两次怎么办?扩展,VST3 插件是由数字音频工作站(VST3 主机)加载并被视为乐器或效果的 DLL;您可以拥有同一个插件的多个实例,并且由主机决定他们如何管理它。这就是我正在处理的情况,其中有同一个插件的多个实例,它们“共享”同一个加载的 DLL。
  • @JohnJoseph,你的意思是DLL在同一个进程或不同进程中多次加载?
猜你喜欢
  • 2011-06-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-23
  • 2013-06-20
  • 2012-12-14
相关资源
最近更新 更多