How to make C (P/invoke) code called from C# “Thread-safe”

后端 未结 4 767
长情又很酷
长情又很酷 2021-02-08 06:43

I have some simple C-code which uses a single global-variable. Obviously this is not thread-safe, so when I call it from multiple threads in C# using P/invoke, things screw up.

4条回答
  •  半阙折子戏
    2021-02-08 06:49

    A common pattern is to have

    • a function that allocates memory for the state,
    • a function that has no side-effects but mutating the passed-in state, and
    • a function that releases the memoy for the state.

    The C# side would look like this:

    Usage:

    var state = new ThreadLocal(NativeMethods.CreateSomeState);
    
    Parallel.For(0, 100, i =>
    {
        var result = NativeMethods.SomeFunction(state.Value, i, 42);
    
        Console.WriteLine(result);
    });
    

    Declarations:

    internal static class NativeMethods
    {
        [DllImport("MyDll.dll", CallingConvention = CallingConvention.Cdecl)]
        public static extern SomeSafeHandle CreateSomeState();
    
        [DllImport("MyDll.dll", CallingConvention = CallingConvention.Cdecl)]
        public static extern int SomeFunction(SomeSafeHandle handle,
                                              int parameter1,
                                              int parameter2);
    
        [DllImport("MyDll.dll", CallingConvention = CallingConvention.Cdecl)]
        internal static extern int FreeSomeState(IntPtr handle);
    }
    

    SafeHandle magic:

    [SecurityPermission(SecurityAction.InheritanceDemand, UnmanagedCode = true)]
    [SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)]
    internal class SomeSafeHandle : SafeHandle
    {
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
        public SomeSafeHandle()
            : base(IntPtr.Zero, true)
        {
        }
    
        public override bool IsInvalid
        {
            get { return this.handle == IntPtr.Zero; }
        }
    
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
        protected override bool ReleaseHandle()
        {
            return NativeMethods.FreeSomeState(this.handle) == 0;
        }
    }
    

提交回复
热议问题