Garbage collection of an object containing a thread with an infinte loop - c#

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.

Related

Confusion about lock and thread-safe variable in .NET [duplicate]

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.

Attempting to acquire a lock on an object when the calling method already has a lock on the same object

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.

.NET GC Accessing a synchronised object from a finalizer

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.

Memory Barrier by lock statement

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.

.NET Working with Locking and Threads

Work on this small test application to learn threading/locking. I have the following code, I would think that the line should only write to console once. However it doesn't seem to be working as expected. Any thoughts on why? What I'm trying to do is add this Lot object to a List, then if any other threads try and hit that list, it would block. Am i completely misusing lock here?
class Program
{
static void Main(string[] args)
{
int threadCount = 10;
//spin up x number of test threads
Thread[] threads = new Thread[threadCount];
Work w = new Work();
for (int i = 0; i < threadCount; i++)
{
threads[i] = new Thread(new ThreadStart(w.DoWork));
}
for (int i = 0; i < threadCount; i++)
{
threads[i].Start();
}
// don't let the console close
Console.ReadLine();
}
}
public class Work
{
List<Lot> lots = new List<Lot>();
private static readonly object thisLock = new object();
public void DoWork()
{
Lot lot = new Lot() { LotID = 1, LotNumber = "100" };
LockLot(lot);
}
private void LockLot(Lot lot)
{
// i would think that "Lot has been added" should only print once?
lock (thisLock)
{
if(!lots.Contains(lot))
{
lots.Add(lot);
Console.WriteLine("Lot has been added");
}
}
}
}
The lock statement ensures that two pieces of code will not execute simultaneously.
If two threads enter a lock block at once, the seconbd thread will wait until the first one finishes, then continue and execute the block.
In your code, lots.Contains(lot) is always false because the DoWork method creates a different Lot object in each thread. Therefore, eah thread adds another Lot object after acquiring the lock.
You probably want to override Equals and GetHashCode in your Lot class and make it compare by value, so that lots.Contains(lot) will return true for different Lot objects with the same values.
lock is essentially a critical section, and will only lock the object while the code within is executed. As soon as the code exists the lock block, the object will be unlocked. So... it makes sense that each thread would (eventually) print to console.
You are creating a new Lot object on each thread, so if you have not defined your own Equals method for the object it makes sense that lots.Contains(lot) will always return false.
You need the lock statement to protect shared data, variables that are read and written by more than one thread at the same time. The "lot" variable doesn't qualify that requirement, every thread creates its own instance of a Lot object. And the reference is stored in a local variable ("lot"), every thread has its own local variables.
The lots field does fit the requirement. There is only one instance of it, because there is only one instance of the Work class, all threads access it. And threads both read and write to the list, respectively through the Contains method and the Add method. Your lock statement prevents a thread from accessing the list at the same time and is correct, Contains can never run at the same time as Add.
You are 95% there, you just missed that each thread has a unique "lot" object. One that cannot have been added to the list before. Every single thread will therefore get a false return from Contains.
If you want the Lot class to have identity, based on the LotID and LotNumber property values instead of just the object instance, then you'll need to give it identity by overriding the Equals() and GetHashCode() method. Check your favorite C# programming book, they all mention this. It doesn't otherwise have anything to do with threading.
Why would you only expect it to run once? You call DoWork in 10 different threads, each one creates its own "new Lot()" object. Were you expecting value comparison of Lot objects? Did you override Equals() and implement IEquatable?

Categories

Resources