26

I'm using such configuration:

  • .NET framework 4.5
  • Windows Server 2008 R2
  • HP DL360p Gen8 (2 * Xeon E5-2640, x64)

I have such field somewhere in my program:

protected int HedgeVolume;

I access this field from several threads. I assume that as I have multi-processor system it's possible that this threads are executing on different processors.

What should I do to guarantee that any time I use this field the most recent value is "read"? And to make sure that when I "write" value it become available to all other threads immediately?

What should I do?

  • just leave field as is.
  • declare it volatile
  • use Interlocked class to access the field
  • use .NET 4.5 Volatile.Read, Volatile.Write methods to access the field
  • use lock

I only need simplest way to make my program work on this configuration I don't need my program to work on another computers or servers or operation systems. Also I want minimal latency so I'm looking for fastest solution that will always work on this standard configuration (multiprocessor intel x64, .net 4.5).

Chi
  • 163
  • 1
  • 2
  • 12
Oleg Vazhnev
  • 23,239
  • 54
  • 171
  • 305
  • You don't state if all threads can update. I assume yes. – paparazzo Oct 24 '12 at 13:56
  • @Blam if this will simplify things then i can make only one thread to update `HedgeVolume`. in general there are several threads updating field. – Oleg Vazhnev Oct 24 '12 at 13:58
  • I think a lock on a static int will do. http://stackoverflow.com/questions/1254750/i-need-to-create-a-thread-safe-static-variable-in-c-sharp-net Not the accepted answer as your question is a little different. See that answer below the accepted. – paparazzo Oct 24 '12 at 14:05

7 Answers7

8

Your question is missing one key element... How important is the integrity of the data in that field?

volatile gives you performance, but if a thread is currently writing changes to the field, you won't get that data until it's done, so you might access out of date information, and potentially overwrite changes another thread is currently doing. If the data is sensitive, you might get bugs that would get very hard to track. However, if you are doing very quick update, overwrite the value without reading it and don't care that once in a while you get outdated (by a few ms) data, go for it.

lock guaranty that only one thread can access the field at a time. You can put it only on the methods that write the field and leave the reading method alone. The down side is, it is slow, and may block a thread while another is performing its task. However, you are sure your data stay valid.

Interlock exist to shield yourself from the scheduler context switch. My opinion? Don't use it unless you know exactly why you would be using it and exactly how to use it. It gives options, but with great options comes great problematic. It prevents a context switch while a variable is being update. It might not do what you think it does and won't prevent parallel threads from performing their tasks simultaneously.

LightStriker
  • 19,738
  • 3
  • 23
  • 27
  • I think often (in 99% of cases) when I do not use anything (even volatile) I still see "latest" value from different threads. is it by accident? it happens so often then i now think that i just don't need to use anything any value always will be "automatically up to date" – Oleg Vazhnev Oct 30 '12 at 20:48
  • Well, when you edit that field is probably quick enough to not cause problem (99% of the time). But I would put `volatile` on it, just in case, and for good readability so that if someone else has to read it, would know what's going on. With threads, better safe than sorry. – LightStriker Oct 30 '12 at 20:52
  • "integrity of the data" is not important for me. I understand that using Interlock, lock i can do "true syncrhonization", also I can syncrhonize using "lock-free" code. But I do not need to synchronize at all. I just want to have "latest" value and that's all. – Oleg Vazhnev Oct 31 '12 at 05:11
  • @javapowered: Then you asnwered your question. `volatile` is what you seek. – LightStriker Nov 05 '12 at 21:02
  • why should I use `volatile` instead of `Volatile`? – Oleg Vazhnev Nov 06 '12 at 18:12
  • @javapowered: It's the same mechanic, exposed differently. The `Volatile` one allows you to do manually the Read/Write of what `volatile` does automatically. Unless you really really need it, just stick with `volatile` which 99% of the time will do the job just fine. (The `Volatile` class also gives access to volatile behavior to language that doesn't have that specific keyword, such has VB.) – LightStriker Nov 06 '12 at 22:22
  • from msdn: "On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears before this method in the code, the processor cannot move it after this method." So I guess that the key word is "On systems that require it". I think probably on system that doesn't require it `Volatile` class doesn't have overhead while `volatile` has overhead on any system. – Oleg Vazhnev Nov 07 '12 at 06:49
  • @javapowered: No, it's exactly the same thing. `volatile` is a shortcut toward `Volatile`. Under the hood, they do exactly the same things, the same check and the same operation. But `volatile` is a keyword that doesn't exist in all language, as it's why it also exists as a .NET class for other CLR language. Also, `volatile` cannot be affected to an array's items, while `Volatile` can manage that. – LightStriker Nov 07 '12 at 07:16
  • i think probably things a little bit more complicated. please refer to this my question http://stackoverflow.com/questions/12425738/difference-between-interlocked-exchange-and-volatile-write and answer "I think Microsoft added Volatile.Write on DotNet 4.5 due to support of ARM processors on Windows 8. Intel and ARM processors differs on memory operation reordering." – Oleg Vazhnev Nov 07 '12 at 09:01
  • @javapowered: So you think when they update JIT definition, they don't take into account new CPU instructions? That's the whole point of JIT in the first place, to optimize for whatever CPU you're using. The idea behind JIT is to give an abstraction level between the code optimization and the code behavior. That the code you write today, will still perform flawlessly in 20 years on completely different CPU set. – LightStriker Nov 07 '12 at 09:10
  • @javapowered LightStriker is correct. They are _largely_ the same thing. volatile means the following, 1. Compiler please don't optimise, 2. Compiler please don't reorder other read/write instructions to the same address, 3. CPU please don't reorder read/write instructions to that address during runtime, 4. CPU pleae ensure you get the most up to date value. Whether you use `Volatile` vs `volatile` in this particular case entirely depends on whether you need that safety for write. Depending on your code, using only `Volatile.Read` might make a difference on x64 with instruction reordering – M Afifi Nov 08 '12 at 09:30
5

You want to use Volatile.Read().

As you are running on x86, all writes in C# are the equivalent of Volatile.Write(), you only need to use this for Itanium.

Volatile.Read() will ensure that you get the latest copy regardless of which thread last wrote it.

There is a fantastic write up here, C# Memory Model Explained

Summary of it includes,

On some processors, not only must the compiler avoid certain optimizations on volatile reads and writes, it also has to use special instructions. On a multi-core machine, different cores have different caches. The processors may not bother to keep those caches coherent by default, and special instructions may be needed to flush and refresh the caches.

Hopefully that much is obvious, other than the need for volatile to stop the compiler from optimising it, there is the processor as well.

However, in C# all writes are volatile (unlike say in Java), regardless of whether you write to a volatile or a non-volatile field. So, the above situation actually never happens in C#. A volatile write updates the thread’s cache, and then flushes the entire cache to main memory.

You do not need Volatile.Write(). More authoratitive source here, Joe Duffy CLR Memory Model. However, you may need it to stop the compiler reordering it.

Since all C# writes are volatile, you can think of all writes as going straight to main memory. A regular, non-volatile read can read the value from the thread’s cache, rather than from main

You need Volatile.Read()

M Afifi
  • 4,645
  • 2
  • 28
  • 48
  • why using `Volatile` class instead of just declaring field as `volatile`? – Oleg Vazhnev Nov 01 '12 at 20:09
  • Declaring it volatile whilst it won't affect the writes on x86/x64, it will effect the compiler. That means that it will not reorder instructions around it. In this particular instance you don't care about writes. Last write wins, you only care about reading the latest value which `Volatile.Read()` accomplishes – M Afifi Nov 04 '12 at 12:12
2

When you start designing a concurrent program, you should consider these options in order of preference:

1) Isolation: each thread has it's own private data
2) Immutability: threads can see shared state, but it never changes
3) Mutable shared state: protect all access to shared state with locks

If you get to (3), then how fast do you actually need this to be?

Acquiring an uncontested lock takes in the order of 10ns ( 10-8 seconds ) - that's fast enough for most applications and is the easiest way to guarantee correctness.

Using any of the other options you mention takes you into the realm of low-lock programming, which is insanely difficult to get correct.


If you want to learn how to write concurrent software, you should read these:

Intro: Joe Albahari's free e-book - will take about a day to read

Bible: Joe Duffy's "Concurrent Programming on Windows" - will take about a month to read

Nick Butler
  • 24,045
  • 4
  • 49
  • 70
0

Depends what you DO. For reading only, volatile is easiest, interlocked allows a little more control. Lock is unnecessary as it is more ganular than the problem you describe. Not sure about Volatile.Read/Write, never used them.

Dan Puzey
  • 33,626
  • 4
  • 73
  • 96
TomTom
  • 61,059
  • 10
  • 88
  • 148
  • i've heard that `volatile` doesn't work between processors, but not sure about that. – Oleg Vazhnev Oct 24 '12 at 14:00
  • What do you mean by "more granular"? – Dan Puzey Oct 24 '12 at 14:01
  • Volatile is an implicit memory barrier, so it should work. That said it does not allow non-volatile acess, so I ararely use it. I mostly use either REF or Interlocked. Lock does a lot more htan just sync read access - you pretty much ahva hugh overhead. SHould more be "less granular", sorry. Lock JUST for rsyncving read acecess is like using a tank to open a door. Yes, it works, but no, you dont normally do it like this. – TomTom Oct 24 '12 at 15:00
0

volatile - bad, there are some issues (see Joe Duffy's blog)

if all you do is read the value or unconditionally write a value - use Volatile.Read and Volatile.Write

if you need to read and subsequently write an updated value - use the lock syntax. You can however achieve the same effect without lock using the Interlocked classes functionality, but this is more complex (involves CompareExchange s to ensure that you are updating the read value i.e. has not been modified since the read operation + logic to retry if the value was modified since the read).

MaLio
  • 2,498
  • 16
  • 23
  • what do you mean by "if all you do is read the value or unconditionally write a value - use Volatile.Read and Volatile.Write" ? it doesn't make sense to only read or write variable. i need both -read and write. – Oleg Vazhnev Oct 24 '12 at 14:36
  • but will everything work "as is"? i'm sure in my program there are a lot of "threads-shared" fields currently and everything works as expected. So I think that I do not need synchronization at all. – Oleg Vazhnev Oct 24 '12 at 14:43
  • @javapowered - only read or write variable - one thread may write a value unconditionally for instance when obtained from user input. another may just read it without performing an operation i.e. passing it on to another operation or service. Then interlocked is just fine. – MaLio Oct 25 '12 at 12:13
  • Can you please elaborate on "volatile - bad", or link to a specific article that has more information. I'll revoke the -1 when you reference some collaboration of, or reasons why "volatile - bad". – csharptest.net Oct 30 '12 at 18:31
  • i also want to see the link why volatile bad – Oleg Vazhnev Oct 31 '12 at 04:07
  • @csharptest.net probably this article is meant http://www.bluebytesoftware.com/blog/2010/12/04/SayonaraVolatile.aspx – Oleg Vazhnev Oct 31 '12 at 04:12
  • Indeed, Thanks javapowered for finding the link. If I get a little time over the weekend I will elaborate a little with some samples. – MaLio Nov 01 '12 at 15:14
0

From this i can understand that you want to be able to read the last value that it was writtent in a field. Lets make an analogy with the sql concurency problem of the data. If you want to be able to read the last value of a field you must make atomic instructions. If someone is writing a field all of the threads must be locked for reading until that thread finished the writing transaction. After that every read on that thread will be safe. The problem is not with reading as it is with writing. A lock on that field whenever its writtent should be enough if you ask me ...

Mihai
  • 518
  • 4
  • 12
0

First have a look here: Volatile vs. Interlocked vs. lock

The volatile modifier shurely is a good option for a multikernel cpu.

But is this enough? It depends on how you calculate the new HedgeVolume value!

  • If your new HedgeVolume does not depend on current HedgeVolume then your done with volatile.

  • But if HedgeVolume[x] = f(HedgeVolume[x-1]) then you need some thread synchronisation to guarantee that HedgeVolume doesn't change while you calculate and assign the new value. Both, lock and Interlocked szenarios would be suitable in this case.

Community
  • 1
  • 1
Lukas Winzenried
  • 1,919
  • 1
  • 14
  • 22