4

Platform: DotNet Core 2 on Linux

Is C# pointer dereference volatile or how to make it volatile?

Our team is working on some crazy stuff require ultra-low latency but still need to be written in C#. We need to get value from a shared memory as low latency as possible and we will busy waiting on this. So pointer reference to shared memory is the fastest way I could image. But really concern about JIT will try to cache the value.

I think Volatile.Read(IntPtr) might do the job but seems IntPtr is an immutable object so the application will create lots of garbage if we keep allocating new ones.

Thanks @Eric pointed out that this is not creating garbage. But my question still there. Does Volatile.Read(IntPtr) will do the job or not? As the IntPtr is not volatile, but the value it pointing to is.

Also any chance I can use compare and swap function on the pointer?

 unsafe
        {
             var access = MemoryMappedFile.CreateFromFile("Test.mem");
            IntPtr ptr = access.SafeMemoryMappedFileHandle.DangerousGetHandle();
             int* p = (int*)ptr.ToPointer();
             p++; //How to get value of this p, if the memory will be updated by another process.

        }
Ming
  • 358
  • 1
  • 10
  • Try using `var something = &p;` – preciousbetine Jan 18 '19 at 10:07
  • Thank you. But will *something be cached value or not? @preciousbetine – Ming Jan 18 '19 at 10:11
  • `*something` would point to the same thing p points to.So if you do something like `var somethingelse = &something` ,you would still get the value of p – preciousbetine Jan 18 '19 at 10:14
  • The fact that C# doesn't allow you to declare a "pointer to volatile" would seem to indicate that it is not needed due to the C# memory-model, but that may just be wishful thinking. You could try calling `Thread.MemoryBarrier()` just before the deference, but (continued...) – Matthew Watson Jan 18 '19 at 10:34
  • (...continued) I don't see why you can't just create the `IntPtr` outside the loop and then inside the loop call `Volatile.Read(ref IntPtr)`. That shouldn't be creating any new objects. – Matthew Watson Jan 18 '19 at 10:35
  • I am very confused as to why you think that intptrs will "create garbage" if you "allocate lots of them". Can you explain this more? It sounds like you are very worried about low-latency coding and yet at the same time you have some very wrong ideas about how garbage collection works. If you explain why you believe that intptrs create garbage, we can help disabuse you of falsehoods you believe that are germane to low-latency programming. – Eric Lippert Jan 18 '19 at 19:59
  • I'm also confused as to why you believe that intptrs being "immutable objects" is relevant; ints, doubles and bools are also immutable objects; are you similarly worried about creating lots of them? This question has a number of details that are very confusing and worrisome. **In order to get unsafe code correct you are required to understand the memory model**. You're turning off a safety system! You need to know what you're doing when you do that. – Eric Lippert Jan 18 '19 at 20:05
  • 2
    I'm also confused about why you're asking if you can do an interlocked compare and swap on a dereferenced pointer. You certainly can. Can you say why it is that you believe it might be impossible? Again, you may have a false belief that needs to be corrected. **This is serious stuff; you really, really have to get this code right**. Unmanaged multithreaded low-lock code is *the hardest code to get correct in C#*. All of your reasoning and beliefs need to be correct. – Eric Lippert Jan 18 '19 at 20:07
  • You say that you are worried about the jitter trying to cache a value, which is equivalent to moving a read backwards in time. You are right to be worried about that, but you're not mentioning the much larger problem: it's the CPU, not the jitter, that you should be stressing about, because modern CPUs have all kinds of caches in them. The jitter's behaviour is actually pretty straightforward. – Eric Lippert Jan 18 '19 at 20:09
  • @MatthewWatson: Your belief that "if this were needed, the C# team would have provided a way" is unsound reasoning and, as you note, wishful thinking. Rather, the correct way to reason about programs is **look at what the C# specification says**. The specification says that certain operations have a special relationship to certain observable side effects. "Volatile read" and "volatile write" are on that list. "Deference a pointer" is not. Therefore you must not assume that pointer dereferences are special. – Eric Lippert Jan 18 '19 at 20:13
  • @MatthewWatson: As you note, introducing an explicit full fence, or introducing an explicit half fence, are two ways of ensuring that a barrier happens. Dereferencing a pointer does not introduce any fence; remember, pointers in C# are intended for *speed* and *interop*. If we introduced a fence on every pointer dereference, that would utterly destroy the speed benefit! – Eric Lippert Jan 18 '19 at 20:16
  • Thank you Eric, I missed that IntPtr is an value type that shouldn’t create lots of garbage. But the new IntPtr just make me a bit uncomfortable that it might do a bit more than I want – Ming Jan 19 '19 at 01:40
  • In your edited code you now say "the intptr is not volatile but the value pointed to is". **If you believe that then you do not understand what volatile means**. The requirement that a fence be introduced is not a property of *values* at all! The need for volatility is a property of *storage locations*. The value stored at that location is irrelevant; what is relevant is whether a fence must be introduced around reads and writes to that location. – Eric Lippert Jan 20 '19 at 18:07
  • Thank you @EricLippert for the warning. I come from C and Java world so my understanding for C# is definitely something I need to work on. For the sentence you quote. Actually I'm saying the difference between "volatile int * p" and "int* volatile p" in C -->https://stackoverflow.com/questions/9935190/why-is-a-point-to-volatile-pointer-like-volatile-int-p-useful – Ming Jan 21 '19 at 07:42

1 Answers1

4
Volatile.Read(ref *p);

An example

But you must guarantee that the address is 4-bytes aligned. Otherwise reading will not be atomic.

OmariO
  • 506
  • 4
  • 11