在多线程环境中从C#调用Delphi DLL时发生访问冲突

Pet*_*erK 8 .net c# delphi pinvoke multithreading

我正在使用P/Invoke从C#调用用Delphi XE2编写的DLL函数.当从单个线程顺序进行调用时,它似乎正在工作.但是,当多个线程调用该函数时,C#主机应用程序System.AccessViolationException似乎随机抛出.

为什么下面的代码会触发访问冲突,我该如何解决?

用于重现问题的最小Delphi库代码:

library pinvokeproblem;

{$R *.res}

uses Windows, SysUtils;

procedure Test(const testByte: byte); stdcall;
begin
  OutputDebugString(PWideChar(IntToStr(testByte)));
end;

exports Test;

end.
Run Code Online (Sandbox Code Playgroud)

用于重现问题的最小C#主机应用程序代码:

[DllImport(
    "pinvokeproblem.dll",
    CallingConvention = CallingConvention.StdCall,
    EntryPoint = "Test")]
private static extern void Test(byte testByte);

public static void Main(string[] args)
{
    for (int i = 1; i <= 1000; i++) // more iterations = better chance to fail
    {
        int threadCount = 10;
        Parallel.For(1, threadCount, new ParallelOptions { MaxDegreeOfParallelism = threadCount }, test =>
        {
            byte byteArgument = 42;
            Test(byteArgument);
            Console.WriteLine(String.Format("Iteration {0}: {1}", test, byteArgument));
        });
     }
}
Run Code Online (Sandbox Code Playgroud)

附加信息:

  • 平台是x64 Windows 7.在.NET 4.0中为x86构建的C#主机应用程序,为32位编译的Delphi DLL.

  • 在多线程Delphi宿主应用程序中使用时,该库似乎工作正常.

  • 具有函数签名的DLL的MSVC版本extern __declspec(dllexport) void __stdcall Test(char testByte)与C#主机一起正常工作(这表明这在某种程度上特定于Delphi).

  • 如果库函数没有返回值(void)和参数,代码将不会失败.

  • 在两个代码中更改调用约定都cdecl没有帮助.

任何想法将不胜感激.

Ond*_*lle 10

所有你需要做的是设置IsMultiThreadTrue(在你的DLL的主要一线begin.. end块)的内存管理器切换到线程安全模式:

IsMultiThread := True;
Run Code Online (Sandbox Code Playgroud)

  • 欢迎.这很容易忘记.我不久前就遇到过一个非常类似的问题,巧合的是C#interop. (2认同)