如何在DLL和Windows二进制内存之间共享静态对象

时间:2012-05-21 23:15:28

标签: c++ memory memory-management dll

我有一些关于DLL的设计问题,我现在正在调用它,因为wikipedia引用它DLL Hell问题如下:

我创建了一个系统,它有多个模块实现为DLL。这些在应用程序中使用,并且可以加载DLL,但并非所有这些都是必需的。如果只做数学之类的东西,它可以链接到'Utilities.dll'并使用它。 问题是,我有一个记录器/跟踪器。这会将所有内容记录到文件和调试控制台,调试控制台只是一个流输出。问题是如何处理多个DLL尝试使用相同的日志类。看到日志类在这个'Utilities.dll'中,像'DataManagers.dll'和其他dll这样的东西也想要使用日志类功能。这包括登录到文件。我目前正在使用关键部分来确保没有发生写入冲突,但是看到关键部分是在usermode中实现的,我必须切换到互斥锁,或者在某些时候类似于拥有内核模式对象。但是,如果我只使用一个关键部分,那么在DLL内存中有多个日志类实例就意味着我会遇到一些严重的问题。

我似乎无法拼凑的是一种方法,所有DLL都可以使用相同的日志类实例,而无需逐个链接到Utilities.dll。我不想将8个dll加载到我的演示项目中,并且让所有8个dll引用带有日志类的那个dll,如果我需要更多的东西,比如日志类,这将是一个连锁反应。有没有办法正确地做到这一点?使用类的功能,在其他DLL和.exe窗口二进制文件中的DLL内使用静态函数,使用相同的“静态”函数,从而在写入日志文件甚至调试控制台的输出流时不会发生冲突。

如果我完全错了并尝试做不可能的事情,请告诉我并帮助尽可能接近这一点。我知道在DLL中使用Singleton模式时会出现类似的问题,但这可以通过

来解决

到目前为止我尝试过:

  • 初始化DLL的类时,会为它们提供日志库的实例,但这会破坏具有所有静态成员的类的目的。

我也发现这个问题是similair(即使是我的全球工具库的名称也是如此...)但它没有回答我的问题并且有一些不同的方法以及存在从'09。 How to mimic the "multiple instances of global variables within the application" behaviour of a static library but using a DLL?

3 个答案:

答案 0 :(得分:5)

你的问题不是" DLL Hell"一点都不。

基本了解DLL的工作原理。每个进程最多加载一次DLL。因此,如果您的DLL被多个其他DLL使用,则每个进程仍然会存在一次。如果您的日志类对象在DLL中实现为单例(例如全局对象),则每个进程都有一个对象。

然后应该保护一个对象以防止在该进程中并发使用。关键部分是流程本地的,与之完美匹配。您不需要互斥锁,因为两个进程都有自己的Utilities.DLL及其对象副本。

如果您的记录器记录到单个固定文件,则可能出现问题。在这种情况下,两个进程将尝试登录到同一文件。这是一个你不想破解的设计问题。保持日志输出分开,因此请确保每个记录器都写入唯一的日志文件。

答案 1 :(得分:0)

使用WinApi的CreatePipe或CreateNamedPipe函数,它是一个使用Windows共享内存的类似队列的通信部分:

    BOOL WINAPI CreatePipe(
  __out         PHANDLE hReadPipe,
  __out         PHANDLE hWritePipe,
  __in          LPSECURITY_ATTRIBUTES lpPipeAttributes,
  __in          DWORD nSize
);

    HANDLE WINAPI CreateNamedPipe(
  __in          LPCTSTR lpName,
  __in          DWORD dwOpenMode,
  __in          DWORD dwPipeMode,
  __in          DWORD nMaxInstances,
  __in          DWORD nOutBufferSize,
  __in          DWORD nInBufferSize,
  __in          DWORD nDefaultTimeOut,
  __in          LPSECURITY_ATTRIBUTES lpSecurityAttributes
);

使用ReadFile和WriteFile通过其他线程/进程内的管道进行通信。

要从管道读取,进程在调用ReadFile函数时使用读取句柄。当满足下列条件之一时,ReadFile返回:写入操作在管道的写入端完成,请求的字节数已被读取或发生错误。

当进程使用WriteFile写入匿名管道时,写入操作直到写入所有字节才完成。如果在写入所有字节之前管道缓冲区已满,则WriteFile不会返回,直到另一个进程或线程使用ReadFile来提供更多缓冲区空间。

使用一个线程来处理输入并将日志写入文件和/或控制台。

有关管道的更多信息:http://msdn.microsoft.com/en-us/library/windows/desktop/aa365780(v=vs.85).aspx

答案 2 :(得分:0)

从下图可以看出,image

在一个进程中多次映射一个DLL实际上非常常见(针对非常流行的观点)!这是基本了解DLL如何工作的问题: - )

在干净的Windows XP系统上,您可以在iexplore.exe进程中看到dxtmsft.dll,ieframe.dll,iepeers.dll等的几个实例。所有这些Dll都只映射到不同的地址。