I read recently about memory barriers and the reordering issue and now I have some confusion about it.
Consider the following scenario:
private object _object1 = null;
private object _object2 = null;
private bool _usingObject1 = false;
private object MyObject
{
get
{
if (_usingObject1)
{
return _object1;
}
else
{
return _object2;
}
}
set
{
if (_usingObject1)
{
_object1 = value;
}
else
{
_object2 = value;
}
}
}
private void Update()
{
_usingMethod1 = true;
SomeProperty = FooMethod();
//..
_usingMethod1 = false;
}
At Update method; is the _usingMethod1 = true statement always executed before getting or setting the property? or due to reordering issue we can not guarantee that?
Should we use volatile like
private volatile bool _usingMethod1 = false;
If we use lock; can we guarantee then every statement within the lock will be executed in order like:
private void FooMethod()
{
object locker = new object();
lock (locker)
{
x = 1;
y = a;
i++;
}
}
The subject of memory barriers is quite complex. It even trips up the experts from time to time. When we talk about a memory barrier we are really combining two different ideas.
Acquire fence: A memory barrier in which other reads & writes are not allowed to move before the fence.
Release fence: A memory barrier in which other reads & writes are not allowed to move after the fence.
A memory barrier that creates only one of two is sometimes called a half-fence. A memory barrier that creates both is sometimes called a full-fence.
The volatile keyword creates half-fences. Reads of volatile fields have acquire semantics while writes have release semantics. That means no instruction can be moved before a read or after a write.
The lock keyword creates full-fences on both boundaries (entry and exit). That means no instruction can be moved either before or after each boundary.
However, all of this moot if we are only concerned with one thread. Ordering, as it is perceived by that thread, is always preserved. In fact, without that fundamental guarentee no program would ever work right. The real issue is with how other threads perceive reads and writes. That is where you need to be concerned.
So to answer your questions:
From a single thread's perspective...yes. From another thread's perspective...no.
It depends. That might work, but I need to have better understanding of what you are trying to acheive.
From another thread's perspective...no. The reads and writes are free to move around within the boundaries of the lock. They just cannot move outside those boundaries. That is why it is important for other threads to also create memory barriers.
The volatile keyword doesn't accomplish anything here. It has very weak guarantees, it does not imply a memory barrier. Your code doesn't show another thread getting created so it is hard to guess if locking is required. It is however a hard requirement if two threads can execute Update() at the same time and use the same object.
Beware that your lock code as posted doesn't lock anything. Each thread would have its own instance of the "locker" object. You have to make it a private field of your class, created by the constructor or an initializer. Thus:
private object locker = new object();
private void Update()
{
lock (locker)
{
_usingMethod1 = true;
SomeProperty = FooMethod();
//..
_usingMethod1 = false;
}
}
Note that there will also be a race on the SomeProperty assignment.
Related
I read recently about memory barriers and the reordering issue and now I have some confusion about it.
Consider the following scenario:
private object _object1 = null;
private object _object2 = null;
private bool _usingObject1 = false;
private object MyObject
{
get
{
if (_usingObject1)
{
return _object1;
}
else
{
return _object2;
}
}
set
{
if (_usingObject1)
{
_object1 = value;
}
else
{
_object2 = value;
}
}
}
private void Update()
{
_usingMethod1 = true;
SomeProperty = FooMethod();
//..
_usingMethod1 = false;
}
At Update method; is the _usingMethod1 = true statement always executed before getting or setting the property? or due to reordering issue we can not guarantee that?
Should we use volatile like
private volatile bool _usingMethod1 = false;
If we use lock; can we guarantee then every statement within the lock will be executed in order like:
private void FooMethod()
{
object locker = new object();
lock (locker)
{
x = 1;
y = a;
i++;
}
}
The subject of memory barriers is quite complex. It even trips up the experts from time to time. When we talk about a memory barrier we are really combining two different ideas.
Acquire fence: A memory barrier in which other reads & writes are not allowed to move before the fence.
Release fence: A memory barrier in which other reads & writes are not allowed to move after the fence.
A memory barrier that creates only one of two is sometimes called a half-fence. A memory barrier that creates both is sometimes called a full-fence.
The volatile keyword creates half-fences. Reads of volatile fields have acquire semantics while writes have release semantics. That means no instruction can be moved before a read or after a write.
The lock keyword creates full-fences on both boundaries (entry and exit). That means no instruction can be moved either before or after each boundary.
However, all of this moot if we are only concerned with one thread. Ordering, as it is perceived by that thread, is always preserved. In fact, without that fundamental guarentee no program would ever work right. The real issue is with how other threads perceive reads and writes. That is where you need to be concerned.
So to answer your questions:
From a single thread's perspective...yes. From another thread's perspective...no.
It depends. That might work, but I need to have better understanding of what you are trying to acheive.
From another thread's perspective...no. The reads and writes are free to move around within the boundaries of the lock. They just cannot move outside those boundaries. That is why it is important for other threads to also create memory barriers.
The volatile keyword doesn't accomplish anything here. It has very weak guarantees, it does not imply a memory barrier. Your code doesn't show another thread getting created so it is hard to guess if locking is required. It is however a hard requirement if two threads can execute Update() at the same time and use the same object.
Beware that your lock code as posted doesn't lock anything. Each thread would have its own instance of the "locker" object. You have to make it a private field of your class, created by the constructor or an initializer. Thus:
private object locker = new object();
private void Update()
{
lock (locker)
{
_usingMethod1 = true;
SomeProperty = FooMethod();
//..
_usingMethod1 = false;
}
}
Note that there will also be a race on the SomeProperty assignment.
I have some code that I have been going over to learn the system and I ran across some code that to me is a code smell and I wouldn't think it would work at all, but it does.
We have two objects, object A and object B. Object A contains a lock object:
private object lockObj = new object();
Object B will grab a lock on object A.lockObj and while B has the lock it calls
A.SomeMethod();
A.SomeMethod() acquires a lock on
this.lockObj
And to show it in code:
ThreadTestOne:
public class ThreadTestOne
{
public object lockObject = new object();
private List<string> lst;
private ThreadTestTwo two;
public List<string> Lst
{
get
{
return this.lst;
}
set
{
this.lst = value;
}
}
public void Run()
{
lst = new List<string>();
two = new ThreadTestTwo();
two.Run(this);
}
public void End()
{
Console.WriteLine("ThreadTestOne.End");
two.End();
}
public void LockMe()
{
Console.WriteLine("ThreadTestOne.LockMe");
lock (this.lockObject)
lst.Add("something");
Thread.Sleep(500);
}
}
ThreadTestTwo:
public class ThreadTestTwo
{
private ThreadTestOne one;
private Thread myThread;
private bool ending = false;
public void Run(ThreadTestOne a)
{
one = a;
myThread = new Thread(new ThreadStart(Consume));
Console.WriteLine("ThreadTestTwo Starting thread");
myThread.Start();
}
public void End()
{
Console.WriteLine("ThreadTestTwo.End");
ending = true;
myThread.Join();
}
public void Consume()
{
while (!ending)
{
Console.WriteLine("ThreadTestTwo one.lockObject");
lock (one.lockObject)
{
Console.WriteLine("two.LockMe");
one.LockMe();
one.Lst.Add("two");
Thread.Sleep(500);
}
}
}
}
When I look over the above code, I think it should break as one.LockMe() should never be able to acquire a lock on lockObj because it ThreadTestTwo already has the lock.
I thought this would result in a deadlock. However, when I run the above example code, it works. Also, the code I was reviewing also works and is currently in production.
The fact that this doesn't result in an exception being thrown is confusing to me. Am I incorrect in assuming this should be an error?
In the code that I was testing originally only reading data after trying to acquire the lock twice so I had thought that the compiler was removing the lock.
However, I looked in the MSIL and saw that the lock is still there.
My next thought was the framework just wasn't acquiring the lock because we are just reading data.
I add a write operation within the lock and it still worked. However, it is possible that I don't fully understand how locking work.
Even though this works, I feel that it is wrong and I am not fully convinced that this will not cause issues in production.
I did find this question:
use the same lock object at two different code block?
Which is similar but I believe my issue is slightly different, I'm asking about locking an object when the calling method has already has a lock on that same object.
Obviously the code I have a question about works and I would like to know how?
Am I incorrect in assuming this is wrong?
There are a couple of issues that I am aware of in the above code.
public field - I know this is wrong, but that is how it is in the code.
Circular reference - I'm aware of the circular reference and know why it is bad.
Thank you for any insight you can provide.
You seem to be under the impression that a class owns a lock (aka monitor). That's not the case - a thread owns a monitor.
Monitors in .NET are re-entrant - if a thread already has the monitor, it can acquire it again. That will increase the "lock count" for it - when the thread releases the monitor the first time, it will just decrease the lock count, but as the count will still be positive, no other thread will be able to acquire the monitor until the original thread has released it again.
From Monitor.Enter (the method that the lock keyword sort-of calls - it actually calls TryEnter, but...):
It is legal for the same thread to invoke Enter more than once without it blocking; however, an equal number of Exit calls must be invoked before other threads waiting on the object will unblock.
Lets say I have a class that is doing something like:
public class Foo
{
private bool _forceStop = false;
private Queue<object> queue;
private void ProcessInBackground()
{
while(!forceStop )
{
Moniter.Enter(queue);
while(!_forceStop && queue.Count == 0)Moniter.Wait(queue);
object data = null;
if (!_forceStop)
data = queue.Dequeue();
Moniter.Exit(queue);
if (data != null)
processData(data);
}
}
...
}
If an object of class Foo is no longer being used and _forceStop is never set to true in that object and assuming ProcessInBackground has been called, will it be collected?
Edit: Resolved, ambiguities added thread safety. Sorry when I wrote the example I just made up a scenario.
(Like Marc, I'm assuming you're referring to the object on which you called ProcessInBackground. I'm also assuming that queue is a field.)
No - you're still referring to queue, which means that field in the object will be read, which means the containing object can't be garbage collected.
Note that just because a method is running in the object does not prevent garbage collection - the garbage collector only cares whether there's any possibility of either the reference itself being used, or a field within the object being read. Demo code to show that:
using System;
using System.Threading;
public class OddFinalizer
{
int field;
public OddFinalizer(int field)
{
this.field = field;
}
~OddFinalizer()
{
Console.WriteLine("OddFinalizer");
}
public void Work()
{
for (int i = 0; i < 5; i++)
{
Console.WriteLine("In loop before last access...");
GC.Collect();
GC.WaitForPendingFinalizers();
Thread.Sleep(1000);
}
Console.WriteLine("Field value: {0}", field);
for (int i = 0; i < 5; i++)
{
Console.WriteLine("In loop after last access...");
GC.Collect();
GC.WaitForPendingFinalizers();
Thread.Sleep(1000);
}
}
static void Main(string[] args)
{
new OddFinalizer(10).Work();
}
}
Results (compiled with /o+, not run in a debugger):
In loop before last access..
In loop before last access..
In loop before last access..
In loop before last access..
In loop before last access..
Field value: 10
In loop after last access...
OddFinalizer
In loop after last access...
In loop after last access...
In loop after last access...
In loop after last access...
Yes, the object data will be collected (assuming processData() doesn't put it into a list).
The GC can handle (managed) threads, the world would end if it couldn't.
But your code is not thread-safe, your DeQueueing after you give up the lock.
A suggestion to improve:
//untested
private bool _forceStop = false;
private object _locker = new object(); // better not depend on queue here
private void ProcessInBackground()
{
while(true)
{
// Moniter.Enter(queue);
lock(_locker)
{
while(!_forceStop && queue.Count == 0)
Moniter.Wait(_locker);
//Moniter.Exit(queue);
if (_forceStop) break;
object data = queue.Dequeue();
}
processData(data);
}
}
Edit:
On second read this is about the containing object. Which is of course kept from collection by the thread.
Assuming by "the object" you mean the instance that owns the method, then if a thread is executing the ProcessInBackground method, then that instance is rooted by the thread (it is arg0, and you are using fields from it in the loop). So no, it will not be collected.
If the "the object" you mean "data", then all but the most recent are certainly eligible. The most recent may depend on the compiler config (did it eliminate the local?) and the CLI (is it checking locals that aren't read?). I'd say "it will probably be eligible, in release/optimised; probably not in debug/unoptimised".
and _forceStop is never set to true, will the object be collected?
No.
An object can't be garbage collected while one of its methods is on a callstack of a thread. The callstack has a reference to the object.
In this case, ProcessInBackground is a method on a callstack of a thread.
Jon's answer corrects my answer - garbage collector works when it's confident no more references will be used, including the this reference. That means that an object may be collected while it has a method on the callstack (this method may be using other methods, but not using any of this instance's own members).
In my own code, I have no finalizers. I have few objects that I care when they get collected. When I expect these to get collected, they aren't on the callstack at that point. If they are collected while they are on the callstack, because .net thinks that's a good thing, no problem by me.
I don't think that detail would change how I should write any code, so I'm going to choose to continue writing code as though my wrong fact above were true, while being slightly mindful of it's wrongness. If my situation is similiar to yours, you may be able to do so as well.
I recently read this article Safe Thread Synchronization as I was curious about the thread safety of calls made from a finaliser. I wrote the following code to test access to a static thread safe collection from a finaliser.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace GCThreadTest
{
class Program
{
static class FinaliserCollection
{
private static Queue<int> s_ItemQueue = new Queue<int>();
private static System.Object s_Lock = new System.Object();
public static void AddItem(int itemValue)
{
lock(s_Lock)
{
s_ItemQueue.Enqueue(itemValue);
}
}
public static bool TryGetItem(out int item)
{
lock(s_Lock)
{
if (s_ItemQueue.Count <= 0)
{
item = -1;
return false;
}
item = s_ItemQueue.Dequeue();
return true;
}
}
}
class FinaliserObject
{
private int m_ItemValue;
public FinaliserObject(int itemValue)
{
m_ItemValue = itemValue;
}
~FinaliserObject()
{
FinaliserCollection.AddItem(m_ItemValue);
}
}
static void Main(string[] args)
{
int itemValueIn = 0;
int itemValueOut = 0;
while (itemValueOut < 10000)
{
System.Threading.ThreadPool.QueueUserWorkItem
(delegate(object value)
{
new FinaliserObject((int)value);
System.Threading.Thread.Sleep(5);
}, itemValueIn);
itemValueIn = itemValueIn + 1;
// This seems to stop finaliser from
// being called?
// System.Threading.Thread.Sleep(5);
int tempItemValueOut = -1;
if (FinaliserCollection.TryGetItem(out tempItemValueOut))
itemValueOut = tempItemValueOut;
}
System.Console.WriteLine("Finished after {0} items created", itemValueOut);
System.Console.ReadLine();
}
}
}
Without the 'Sleep' call in the while loop this code seems to run fine but is it really safe from deadlocking? Would it ever be possible for a finaliser call to be made while a queued thread pool item is accessing the static collection? Why does adding the 'Sleep' to the main threads while loop appear to stop all finalisers from being called?
Wow. What the... This is the most bizarre piece of code I've ever seen. #.#
First of all, what finalizer call are you referring to? The only finalizer I see is the finalizer for the FinaliserObject, which will be called 10,000 times, and can be called independently of whatever's going on on the static collection. I.E. yes, those objects can be destroyed while other objects are being dequeued from the collection. This isn't an issue.
The static collection itself won't be cleaned up until the app itself exits.
Keep in mind that there's absolutely no guarantee when or if those finalizers will be called before the app itself exits. Your static collection could be completely empty when you exit.
Worse, you're assigning itemValueOut to whatever the last value you pull out of the queue is... which is NOT the number of items created, as you imply in your WriteLine(). Because those destructors are called in any possible order, you could theoretically add to the queue 10,000, 9,999, 9,998, ... 2, 1, in that order.
Which is further an issue, because you're removing from the queue 10,000 times, but on the last loop, it's very possible there won't be an object to dequeue, in which case you're guaranteed to get -1 for the number of items returned (even if the other 9,999 items worked successfully).
To answer your question, this code cannot deadlock. A deadlock would happen if AddItem() called TryGetItem(), but those locks are pretty much guaranteed to keep each other out of the static collection while adding or removing items.
Where you're tempting fate is that you can exit your app without all of the FinaliserObjects having added themselves to the queue. Meaning one of the finalizers could fire and try to add to the FinaliserCollection, but the FinaliserCollection has already been disposed. What you're doing in the finaliser is terrible.
But yes, a finalizer call can happen while you're calling FinaliserCollection.TryGetItem(). The finalizer will block and wait until TryGetItem() emerges from the lock(), at which point it will add another item. This is not an issue.
As for the sleep() command, you're probably just throwing the timing of the garbage collection off. Remember, your objects won't be collected/finalized until the GC decides it needs the resources.
Sorry for being so emphatic... I know you're just trying to test a concept but I really don't understand why you would want to do what you're trying to do in the finalizer. If there's really a legitimate goal here, doing it in the finalizer is not the correct answer.
Edit
From what I'm reading and what Sasha is saying, no you will not have a deadlock. The finalizer thread may be blocked waiting for the lock, but the GC will not wait for the finalizer, and will thus unsuspend the threads, allowing the locks to be released.
In any case, this is a very strong argument for why you shouldn't be making calls like this in a finalizer... the finalizer is only for releasing unmanaged resources. Anything else is playing roulette.
I used this pattern in a few projects, (this snipped of code is from CodeCampServer), I understand what it does, but I'm really interesting in an explanation about this pattern. Specifically:
Why is the double check of _dependenciesRegistered.
Why to use lock (Lock){}.
Thanks.
public class DependencyRegistrarModule : IHttpModule
{
private static bool _dependenciesRegistered;
private static readonly object Lock = new object();
public void Init(HttpApplication context)
{
context.BeginRequest += context_BeginRequest;
}
public void Dispose() { }
private static void context_BeginRequest(object sender, EventArgs e)
{
EnsureDependenciesRegistered();
}
private static void EnsureDependenciesRegistered()
{
if (!_dependenciesRegistered)
{
lock (Lock)
{
if (!_dependenciesRegistered)
{
new DependencyRegistrar().ConfigureOnStartup();
_dependenciesRegistered = true;
}
}
}
}
}
This is the Double-checked locking pattern.
The lock statement ensures that the code inside the block will not run on two threads simultaneously.
Since a lock statement is somewhat expensive, the code checks whether it's already been initialized before entering the lock.
However, because a different thread might have initialized it just after the outer check, it needs to check again inside the lock.
Note that this is not the best way to do it.
The double-check is because two threads could hit EnsureDependenciesRegistered at the same time, both find it isn't registered, and thus both attempt to get the lock.
lock(Lock) is essentially a form of mutex; only one thread can have the lock - the other must wait until the lock is released (at the end of the lock(...) {...} statement).
So in this scenario, a thread might (although unlikely) have been the second thread into the lock - so each must double-check in case it was the second, and the work has already been done.
It's a matter of performance.
The initial test lets it bail out quickly if the job is already done. At this point it does the potentially expensive lock but it has to check it again as another thread could have already registered it.
The double checked locking pattern is roughly:
you have an operation that you want to conditionally perform once
if (needsToDoSomething) {
DoSomething();
needsToDoSomething = false;
}
however, if you're running on two threads, both threads might check the flag, and perform the action, before they both set the flag to false. Therefore, you add a lock.
lock (Lock) {
if (needsToDoSomething) {
DoSomething();
needsToDoSomething = false;
}
}
however, taking a lock every time you run this code might be slow, so you decide, lets only try to take the lock when we actually need to.
if (needsToDoSomething)
lock (Lock) {
if (needsToDoSomething) {
DoSomething();
needsToDoSomething = false;
}
}
You can't remove the inner check, because once again, you have the problem that any check performed outside of a lock can possibly turn out to be true twice on two different threads.
The lock prevents two threads from running ConfigureOnStartup(). Between the if (!_dependenciesRegistered) and the point that ConfigureOnStartup() sets _dependenciesRegistered = true, another thread could check if it's registered. In other words:
Thread 1: _dependenciesRegistered == false
Thread 2: _dependenciesRegistered == false
Thread 1: ConfigureOnStartup() / _dependenciesRegistered = true;
Thread 2: Doesn't "see" that it's already registered, so runs ConfigureOnStartup() again.