What is the cost of the volatile keyword in a multiprocessor system?
-
05-07-2019 - |
Question
we're running into performance issues, and one potential culprit is a centralized use of a volatile singleton. the specific code is of the form
class foo {
static volatile instance;
static object l = new object();
public static foo Instance {
if (instance == null)
lock(l) {
if (instance == null)
instance = new foo();
}
return foo();
}
}
this is running on an 8-way box, and we're seeing context switching to the tune of 500,000 per second. typical system resources are fine - 25% cpu util, 25% memory util, low IO, no paging, etc.
does using a volatile field induce a memory barrier or any kind of cpu cache reload? or does it just go after main memory every time, for that field only?
Solution
lock
does induce a memory barrier, so if you are always accessing instance in a lock you don't need the volatile.
According to this site:
The C# volatile keyword implements acquire and release semantics, which implies a read memory barrier on read and a write memory barrier on write.
OTHER TIPS
One thing volatile will not do is cause a context switch. If you're seeing 500,000 context switches per second, it means that your threads are blocking on something and volatile is not the culprit.
Sadly, the singleton takes a bad rap for just about everything :)
This isn't my domain of expertise, but as far as I know there's nothing special about volatile other than the compiler/run-time NOT re-ordering read/writes (to the variable) for optimization purposes.
Edit: I stand corrected. Not only does volatile introduce memory barriers, but what goes on (and incidentally, performance) depends largely on the particular CPU involved. See http://dotnetframeworkplanet.blogspot.com/2008/11/volatile-field-and-memory-barrier-look.html
This is why you still need the lock.
Questions which may/may not have been answered already:
- What is your singleton instance actually doing? Maybe the instance code needs to be refactored...
- What's the thread count of the running process? An 8 way box won't help you if you have an abnormally high thread count.
- If it's higher than expected, why?
- What else is running on the system?
- Is the performance issue consistent?
In your example here, volatile should not be the subject of any "slowdown". The lock() however, can involve huge roundtrips to the kernel, especially if there's a lot of contention for the lock.
There is really no need to lock your singleton in this case, you could just do
class Foo {
static Foo instance = new Foo();
public static Foo FooInstance() {
return instance ;
}
}
Ofcourse, if 'instance ' is used in a lot of different threads, you'd still have to lock() anything that alters that Foo, unless all methods/properties of Foo is readonly. e.g.
class Foo {
static Foo instance = new Foo();
object l = new object();
int doesntChange = 42;
int canChange = 123;
public static Foo FooInstance() {
return instance ;
}
public void Update(int newVal) {
lock(l) { // you'll get a lot of trouble without this lock if several threads accesses the same FOO. Atleast if they later on read that variable
canChange = newVal;
}
public int GetFixedVal() {
return doesntChange; //no need for a lock. the doesntChange is effectivly read only
}
}
There's really no need for the use of volatile for a singleton, as you're setting it exactly once - and locking the code the sets it. See Jon Skeet's article on singletons for more info.
The short answer is, Yes it creates a memory barrier (flushes everything and goes to main memory, not just that single variable), but No it will not be the cause of context switching.
Also, as others have mentioned, I don't believe volatile is necessary here.