使用 PInvoke 包装的 C++ 库的并行调用引发 System.AccessViolationException

Parallel invocations of C++ library wrapped with PInvoke raises System.AccessViolationException

我正在使用 PInvoke 技术从 .NET Framework 4.6.1 调用 C++ dll (CoolProp library)。

以下 C# 代码:

[DllImport("CoolProp", EntryPoint = "CSharp_PropsSI")]
public static extern double PropsSI(string Output, string Name1, double Prop1, string Name2, double Prop2, string Ref);

包装库的主要功能之一的声明。

在单线程环境下调用时一切正常。 当我尝试使用 System.Threading.Tasks:

并行调用此外部函数时,出现 问题
[TestMethod]
public async Task TestAsyncMethod()
{
    double tco = 30;
    string refrigerant = "R134a";

    var t1 = Task.Run(() => CoolProp.PropsSI("P", "T", tco + 273.15, "Q", 0.0, refrigerant));
    var t2 = Task.Run(() => CoolProp.PropsSI("P", "T", tco + 273.15, "Q", 0.0, refrigerant));

    var res = await Task.WhenAll(t1, t2);

    Assert.AreEqual(res[0], res[1]);
}

上面的单元测试失败并引发以下异常:

Message: 
    Test method XRACModel_UnitTest.CoolingCircuitTest.TestAsyncMethod threw exception: 
    System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
  Stack Trace: 
    CoolPropPINVOKE.PropsSI(String jarg1, String jarg2, Double jarg3, String jarg4, Double jarg5, String jarg6)
    CoolProp.PropsSI(String Output, String Name1, Double Prop1, String Name2, Double Prop2, String FluidName) line 141
    CoolingCircuitTest.Method(Double tco, Double tev, Double sbc, String refrigerant) line 226
    <>c__DisplayClass3_0.<TestAsyncMethod>b__0() line 214
    Task`1.InnerInvoke()
    Task.Execute()
    --- End of stack trace from previous location where exception was thrown ---
    TaskAwaiter.ThrowForNonSuccess(Task task)
    TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
    TaskAwaiter`1.GetResult()
    <TestAsyncMethod>d__3.MoveNext() line 217
    --- End of stack trace from previous location where exception was thrown ---
    TaskAwaiter.ThrowForNonSuccess(Task task)
    TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
    ThreadOperations.ExecuteWithAbortSafety(Action action)

问题的原因是什么?为什么用单线程没问题,多线程就不行了? 它可能是 C++ 库(从回购协议中的一个问题来看,它似乎不是 link)?

当然,C++ 库本身不是线程安全的,例如有一个静态错误字符串 https://github.com/CoolProp/CoolProp/blob/master/src/CoolProp.cpp#L59,它可以由异常处理和其他一些地方同时设置。如果在多个线程上设置它可能是导致内存损坏的故障模式,这当然是未定义的行为,应该避免。