在主机应用程序和DLL中使用相同的互斥锁

时间:2015-03-08 15:09:47

标签: delphi mutex

我有一个多线程应用程序,可以动态加载dll(插件)。我在DLL中有线程。主机应用程序和DLL之间是我自己的SDK,目的是启用与DLL插件(库接口)的通信,并定义主机应用程序和dll(数据结构等)之间的共享资源。

主机应用程序正在使用WinAPI函数CreateMutex创建一个互斥对象,并将已创建的互斥锁的THandle传递给我加载的每个dll。当DLL中的线程正在更改公共资源时,它使用互斥锁来保护它。正如我所说,我使用WinAPI.Windows单元调用CreateMutex和所有其他互斥相关的函数(Release等..)。

我的想法是制作SDK跨平台,因此我即将修改SDK,我想摆脱单位WinAPI.Windows和所有Windows相关的东西当然。

我包含System.SyncObjs以使用TMutex类。现在我不太确定如何让我知道关于那门课的问题。一种选择是将TMutex传递给我的DLL,但我认为如果我想在我的SDK中保留原始数据类型,这不是一个选项,因为SDK必须可用于其他语言,如C ++,C#...等其他想法穿过我的介意是使用命名的互斥锁,只需将名称(字符串)传递给DLL。

根据MSDN:如果互斥锁是一个命名的互斥锁,并且该函数调用之前存在该对象,则返回值是现有对象的句柄,GetLastError返回ERROR_ALREADY_EXISTS,忽略bInitialOwner,调用线程为未授予所有权。但是,如果调用者具有有限的访问权限,则该函数将失败并显示ERROR_ACCESS_DENIED,并且调用者应使用OpenMutex函数。

所以我假设DLL在调用TMutex.Create(...,' MyMutex')时可以使用现有的名为mutex(MyMutex)。

我是对的吗?

感谢您的帮助和建议。我真的很感激!

2 个答案:

答案 0 :(得分:2)

Windows互斥可以"共享"跨进程(在exe和DLL中更是如此) - 你有两种方法:

  1. 使用指定的互斥锁。使用OpenMutex()API获取已存在的互斥锁的句柄 - 您需要确保在CreateMutex()之后调用它,否则它将无法找到要打开的互斥锁。
  2. 对未命名的互斥锁使用DuplicateHandle(),它返回一个在目标进程中有效的新句柄(在DLL的情况下可以是相同的)
  3. 通常,Delphi中的API包装器太过限制了复杂的"场景。即使Delphi没有公开它们,直接使用Windows API也可以完全访问底层功能。转而之后,您将了解更多有关Windows如何工作的信息,而且您可以随时在Delphi外部进行回收......并且您不需要使用丑陋的黑客来包装不需要的东西包裹在界面等...

    如果您需要跨平台功能,请为OS互斥体实现编写自己的包装器 - 不要依赖Delphi的包装器。

答案 1 :(得分:1)

不允许在运行时包之外的模块之间传递类实例。这不是一种有效的互操作形式。

所以我认为最干净的解决方案是用接口包装TMutex。您可以在任何类型的模块之间传递接口,甚至是由不同编译器编译的模块。

有各种不同的互斥体可用,但在我看来,显而易见的选择是包裹TMonitor。界面很简单:

type
  IMutex = interface
    procedure Acquire; stdcall;
    procedure Release; stdcall;
  end;

在可执行文件和DLL之间传递此接口是完全安全的。

实施可能如下:

type
  TXplatMutex = class(TInterfacedObject, IMutex)
  public
    procedure Acquire; stdcall;
    procedure Release; stdcall;
  end;

procedure TXplatMutex.Acquire;
begin
  TMonitor.Enter(Self);
end;

procedure TXplatMutex.Release;
begin
  TMonitor.Exit(Self);
end;

您可以用这种方式包装您喜欢的任何互斥锁。我选择TMonitor因为它在所有平台上都受支持,并且是Embarcadero库代码用于同步的主要工具。