Atomic unlocked access to 64bit blocks of Memory Mapped Files in .NET
Asked Answered
Y

1

1

We need to share very efficiently block of constantly changing information between two processes. Information fits in 64bits block of memory - so inside one process we'd be able to use Interlocked operations (or probably even just ordinary reads/writes) to ensure lock-free access to correct state of information (not just partially written).

How can we write and ready block of 64bit data into MMF without locking and synchronization in order to make sure that we don't read partially written data? Aren't writes of this size atomic by itself on 64bit architecture? But aligning could probably make it non-atomic, correct?

So is using Interlocked operations (e.g. via the way described in this question: How to use interlocked operations against memory-mapped files in .Net) on MMF the way to go? But couldn't we have the problems with aligning even in this case (as MMF is block of memory and so .NET might not control it's aligning as it does with variables)?

Yarrow answered 23/5, 2014 at 18:15 Comment(5)
Not sure how this relates at all to MMF. All issues discussed here apply to any access to unmanaged memory. So your question becomes "How to atomically write to unmanaged memory?" Right?Simmers
While I'm not completely clear on what you're asking, I'll offer this: you're going to need some synchronization method. If you're looking to maximum parallel work, consider partitioning you data. If you can get Interlocked to work great, otherwise good old fashioned named semaphores or mutexes are likely your best bet.Mebane
Do I understand you correct, that you would like to not use the interlocked operations, that instead you intend simply to update the memory as fast as you can, and the reader process wants only to be guaranteed to get fully written value when ever it is ready for it?Inconsequent
@Simmers you are correct - I need a way how I'm guaranteed to write through into the unmanaged memory (not just local cache) an write register-size values atomically.Yarrow
@Inconsequent - Yes you are correct. Also I need to be sure that reader always reads the most recent value from the memory location (and CPU or CLR isn't optimizing access to same memory location by reading memory location just once and than using cached value - as this can happen in single process without using volatile, Interlocked, or other memory fencing constructs)Yarrow
I
2

How can we write and ready block of 64bit data into MMF without locking and synchronization in order to make sure that we don't read partially written data? Aren't writes of this size atomic by itself on 64bit architecture? But aligning could probably make it non-atomic, correct?

Memory mapped files are page aligned under the covers, so keep your data aligned in your MMF. Then, if you write a 64-bit integer on a 64-bit processor with a 64-bit instruction to a 64-bit aligned location, there should be no chance of another processor reading a partially written value at that location.

[Edit] See the article Managing Memory-Mapped File (MSDN) which describes one implementation of MMF files as system page files. Also see this Wiki as general info on MMF which states MMFs are always page aligned.

So is using Interlocked operations (e.g. via the way described in 'cited' question: How to use interlocked operations against memory-mapped files in .Net) on MMF the way to go? But couldn't we have the problems with aligning even in this case (as MMF is block of memory and so .NET might not control it's aligning as it does with variables)?

There shouldn't be any alignment issues with the example you've cited.

Inconsequent answered 23/5, 2014 at 20:9 Comment(9)
Can you share a source of information where you found out that MMF are page aligned under the covers? Once I know this for sure than this 100% answers my question! (Yes - you understood my intentions very precisely - I don't care about all updates, I just care about seeing fully written value).Yarrow
By the way - without Interlocked operations or Memory barrier - am I guaranteed that the information from writer will be written directly to the memory, not just a temporary local cache? Basically same kind of problem that can happen with reader thread reading non-volatile variable?Yarrow
@Jen All memory sections are page aligned. This is documented, and it makes sense because the memory mapping unit of the CPU thinks in pages.; Without memory barriers, volatile writes or interlocked operations you have very little visibility guarantees. My advice: Use interlocked, you will not be able to achieve meaningfully better performance. I would have added my own answer but this pretty much covers it.Simmers
@jen - you should use volatile keyword to prevent optimization of the reads and writes.Inconsequent
@jen - on second thought, I don't know enough about the implementation of volatile in CLR. This posting might help #1965231Inconsequent
@Simmers - thanks for your comment - it added extra pieces of information that I needed.Yarrow
This doesn't handle cases of atomically incrementing or decrementing integer values though, right? I am trying to port some c++ code that uses InterlockedIncrement etc... but can't seem to find a .NET equivalent method.Concordia
@StephenDrew - right, this has nothing to do with incrementing or decrementing, but atomically writing a value. .NET has InterlockedIncrement . See Interlocked.Increment in System.ThreadingInconsequent
Thanks Les, I came up with a solution that was based on how the underlying UnmanagedMemoryAccessor writes integers, and used PInvoke to use the Windows InterlockedIncrement/InterlockedDecrement API functions instead. .NET Interlocked.Increment cannot work in this situation. Seems to be a bit of an oversight in the support for memory-mapped files in .NETConcordia

© 2022 - 2024 — McMap. All rights reserved.