Вопрос

In order to perform interlocked reads I have used InterlockedCompareExchange function a la

value = InterlockedCompareExchange(ptr, 0, 0);

Now I stumbled upon unusual situation.
I want to use this interlocked "read" on a read-only (write-protected) memory page. The result is "Access violation writing location x"...

So I guess this is by design? I understand that InterlockedCompareExchange is often a used as a "write" instruction. But why is access violation trigger included in this particular case?

What are the alternatives to InterlockedCompareExchange in order to perform interlocked read?


Update: I tried using

value = InterlockedCompareExchange(ptr, 0, -1);

when I know that the value at ptr is never negative, but this triggers the access violation also, even though in this case there certainly isn't any writing going on. So I guess this is by design with this instruction...
But why and how to get around that?


Update2: More details about why I started using interlocked reads.
I left my question intentionally vague. I am generally interested in the topic, that is - both skipping the cache and having atomic reads, including atomic 64-bit reads.

The reason why I started wondering is that .NET uses CompareExchange for interlocked reading inside
System.Threading.Interlocked.Read(ref Int64 location)
method.
The MSDN states for this .NET Interlocked.Read method: "The Read method is unnecessary on 64-bit systems, because 64-bit read operations are already atomic. On 32-bit systems, 64-bit read operations are not atomic unless performed using Read."

Also, MSDN states for (C-language) InterlockedCompareExchange64 function that unaligned operations are not permitted in any case: "The variables for this function must be aligned on a 64-bit boundary; otherwise, this function will behave unpredictably on multiprocessor x86 systems and any non-x86 systems".
So according to that text also .NET should never have unaligned Int64 variables. But then why interlocked reading?

Это было полезно?

Решение

The memory must be writable in case the comparison succeeds. This is true even if you know that it won't succeed due to your program logic. On x86, this is enforced by the processor. According to the processor documentation, the cmpxchg instruction generates a write cycle even if the comparison fails.

It is not clear what the intention of the interlocked operation is. If you merely want to read the value atomically (i.e., without tearing), then you can simply issue a read, because properly aligned reads and writes are already atomic. If you want to access the memory with specific semantics, you can stick a _ReadBarrier, _WriteBarrier, MemoryBarrier, or fence before/after the instruction as desired. Starting in Visual Studio 2005, volatile reads are performed with acquire semantics and volatile writes are performed with release semantics.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top