none
Interlocked.CompareExchange of unmanaged memory from VB RRS feed

  • Question

  • As part of an IPC implementation which uses shared memory, and doubly linked lists I need to perform link exchanges atomically.  I believe this class/method will do this for managed values. But I need the operation to be performed on values held in memory shared between two processes.

    For me to do the compare and exchange myself, obviously, I have to use Marshal to pull the values out of shared memory, and to put them back into shared memory, and can not make this atomic, such that two competing processes would interfere with each other.

    I suspect that Interlocked.CompareExchange can not do this.  If so, then perhaps a good follow on question, is there any way I can declare a short section of code to be atomic?

    Using this atomic operator is key to eliminating very performance costly use of inter-process resource locking, such as Mutex. I'm working with a design that does not use them.

    I don't know how this is implemented at it's core. Is it a single machine instruction and as such, provides the atomicity?


    Lee Gillie, CCP Online Data Processing, Inc. - Spokane, WA

    Thursday, May 10, 2012 7:55 PM

Answers

  • Maybe it's not as bad as a Mutex but it's still far more expensive than the "real thing". The real "compare exchange" is really a single instruction in x86, using a PInvoke call will turn this single instruction into hundreds of instructions. And usually "compare exchange" is used in a loop and if the contention is high those hundreds will multiply, every loop iteration you'll make another PInvoke call.
    • Marked as answer by Lee Gillie Thursday, May 10, 2012 8:53 PM
    Thursday, May 10, 2012 8:31 PM
    Moderator

All replies

  • Sure I can do this by calling on Kernel32 !  Simple.

    Lee Gillie, CCP Online Data Processing, Inc. - Spokane, WA

    • Marked as answer by Lee Gillie Thursday, May 10, 2012 8:04 PM
    • Unmarked as answer by Lee Gillie Thursday, May 10, 2012 8:53 PM
    Thursday, May 10, 2012 8:04 PM
  • "Sure I can do this by calling on Kernel32 !"

    Umm, yes but the overhead of a PInvoke call will defeat any benefit of using interlocked operations.

    Thursday, May 10, 2012 8:10 PM
    Moderator
  • You are saying that a PInvoke call within the process will cost as much or more as using a named Mutex across processes?

    Lee Gillie, CCP Online Data Processing, Inc. - Spokane, WA

    Thursday, May 10, 2012 8:17 PM
  • Maybe it's not as bad as a Mutex but it's still far more expensive than the "real thing". The real "compare exchange" is really a single instruction in x86, using a PInvoke call will turn this single instruction into hundreds of instructions. And usually "compare exchange" is used in a loop and if the contention is high those hundreds will multiply, every loop iteration you'll make another PInvoke call.
    • Marked as answer by Lee Gillie Thursday, May 10, 2012 8:53 PM
    Thursday, May 10, 2012 8:31 PM
    Moderator
  • Mike,

    I appreciate your response, and taking time to explain it.  Thank you.

    It seems pretty clear to me I need to implement my core functionality in C++ and then provide Interop to VB. The iterative and chugging work happens in the C++ DLL. Within the context of C++ I'll resolve contention, and work with the unmanaged memory blocks, points, and those fiddles.

    I tried to chase this down with my own design using Mutex already, and paid a huge price. I could not pump very much more data through it than TCP, about 1.5 gb/sec TCP streams, and about 2.1 gb/sec my MMF stream.  But I believe in doing away with all Mutex in favor of a couple of simple and fast events, and this InterlockedCompareExchange function to manage the doubly circular linked list, I should be able to attain 6-7 gb/sec.  That makes it sufficiently worth the time, and using this over TCP when the ends of the channel are on the same computer. Putting all the "groink" in C++ will minimize the number of managed/unmanaged bridges I need to cross to a minimum.


    Lee Gillie, CCP Online Data Processing, Inc. - Spokane, WA

    Thursday, May 10, 2012 8:53 PM
  • "It seems pretty clear to me I need to implement my core functionality in C++ and then provide Interop to VB."

    This seems to be the case. Alternatively you may be able to use C# because there it is possible to use the Interlocked class. The problem with using the Interlocked class with unmanaged memory is that it takes a ref rather than a pointer but with C#'s unsafe pointer you can do a trick to get a ref to unmanaged memory. Here's a simple example with Interlocked.Add in case you need such a thing:

    using System;
    using System.Threading;
    using System.Runtime.InteropServices;
    internal struct Counter {
        private int value;
        public void Increment() {
            Interlocked.Add(ref value, 1);
        }
    }
    unsafe class Program {
        static void Main(string[] args) {
            Counter* p = (Counter*)Marshal.AllocHGlobal(sizeof(Counter));
            p->Increment();
        }
    }

    When compiled in Release mode the code generated for p->Increment will be a single x86 instruction: lock inc dword ptr [eax].

    • Proposed as answer by ILNumerics GmbH Wednesday, September 13, 2017 10:53 AM
    Thursday, May 10, 2012 9:00 PM
    Moderator