All, I am monitoring my outlook inbox for some emails and parses that based on the content. I do this by running a console application and triggering a timer as shown below. The problem is this gets garbage collected after some time and I have to restart the app manually. I cannot run this inside a windows service as I get some permission issues while calling the Outlook api. Please see my code below
I tried doing a GC.SuppressFinalize(), GC.KeepAlive() on the timer object but no avail.
class Program
{
private static System.Timers.Timer _timer = new System.Timers.Timer();
static void Main(string[] args)
{
_timer.Interval = 10000;
_timer.Start();
_timer.Elapsed += Timer_Elapsed1;
Console.ReadLine();
}
}
private static void Timer_Elapsed1(object sender, System.Timers.ElapsedEventArgs e)
{
try
{
_timer.Stop();
AddNumbers(2, 2);
Console.WriteLine("The current time now is :{0}", DateTime.Now.ToString());
GC.SuppressFinalize(_timer);
_timer.Start();
}
catch (Exception ex)
{
_timer.Start();
Console.WriteLine("Timer restarted from exception");
}
finally
{
_timer.Start();
}
}
private static void AddNumbers(int x, int y)
{
var sum = x + y;
Console.WriteLine(sum);
}
In the scope of your example application your Timer is not being garbage collected so you must be getting another error. Also, please see my note and example below about GC.SuppressFinalize because what you're implying and what it does are two different things.
Loop instead of Timer
Just a suggestion: When using a Timer and the Elapsed event calls the timer to stop and then start again once complete this is a sign you need to have a simple loop running instead with a thread wait.
Since this is a console app and there are no other threads required I'll post a simple looping example that, IMO, would be more efficient and easier to manage.
using System;
using System.Threading;
namespace Question_Answer_Console_App
{
class Program
{
private const int SleepTimeMS = 10000;
static void Main(string[] args)
{
ThreadPool.QueueUserWorkItem(new WaitCallback((state) =>
{
while (true)
{
Thread.Sleep(SleepTimeMS);
AddNumbers(2, 2);
Console.WriteLine("The current time now is :{0}", DateTime.Now.ToString());
}
}));
Console.Read();
}
private static void AddNumbers(int x, int y)
{
var sum = x + y;
Console.WriteLine(sum);
}
}
}
GC.SuppressFinalize Information
Also, GC.SuppressFinalize does not have anything to do with garbage collection; it just tells the garbage collector, that when collected, not to run the finalizer on the object (the destructor method in C#). This is useful when there are items already disposed and you don't want to reproduce the work... For example if you're object is IDisposable, and you place the Dispose method in the destructor, and the user properly disposes of it when it is being used then you may want to skip the destructor. Here's an example of using GC.SuppressFinalize properly.
public class SomethingDisposable : IDisposable
{
public void Dispose()
{
//Dispose of some unmanaged resources or something.
GC.SuppressFinalize(this); //We can safely skip the Destructor method (Finalizer)
}
~SomethingDisposable() => Dispose(); //Just incase the object is garbage collected and never properly disposed.
}
GC.SuppressFinalize Example
And just for show here's a console app that illustrates the GC.SuppressFinalize in work. I make 2 IDisposable objects. The first I actually dispose of properly with a using statement and the second I don't. Once they are out of scope they are up for garbage collection. I intentionally call the garbage collector and wait for all finalizers to be called so that we can immediately see results.
Notice the disposed object DOES NOT call the finalizer and the object that was not disposed does (which in turn calls dispose... which is the proper way to implement it.)
using System;
namespace Question_Answer_Console_App
{
class Program
{
private const string DisposableTestId = "Disposable-Test";
private const string FinalizingTestId = "Finalizing-Test";
static void Main(string[] args)
{
TestDisposing();
Console.WriteLine();
TestFinalizing();
GC.Collect();
GC.WaitForPendingFinalizers();
Console.Read();
}
private static void TestDisposing()
{
using (var disposingTest = new TestSuppressFinalize(DisposableTestId))
PrintTesting(disposingTest);
}
private static void TestFinalizing()
{
var finalizingTest = new TestSuppressFinalize(FinalizingTestId);
PrintTesting(finalizingTest);
}
private static void PrintTesting(TestSuppressFinalize finalizingTest)
=> Console.WriteLine($"Testing {finalizingTest.TestId.ToString()}");
}
public class TestSuppressFinalize : IDisposable
{
public TestSuppressFinalize(string testId) => TestId = testId;
public string TestId { get; }
public void Dispose()
{
Console.WriteLine($"Disposed {TestId.ToString()}");
GC.SuppressFinalize(this);
}
~TestSuppressFinalize()
{
Console.WriteLine($"Finalized {TestId.ToString()}");
Dispose();
}
}
}
Output:
Testing Disposable-Test
Disposed Disposable-Test
Testing Finalizing-Test
Finalized Finalizing-Test
Disposed Finalizing-Test
Related
There is a class in my project called DataParse. I am making multiple connections with Ethernet. Every time a new connection is opened I create a new class as follows. Also, there is one timer in this class.
public Dictionary<string, DataParse> classDictionary = new Dictionary<string, DataParse>();
Connect Code
string IpAddress = Ip.Text;
int Port = Convert.ToInt32(PortName.Text);
var IpPort = IpAddress + ":" + Port;
classDictionary.Add(IpPort, new DataParse());
classDictionary[IpPort].DataParseRun(IpPort);
I want to destroy the created class when the connection is closed. I want to destroy the timer with the class.
I implemented a method like this to destroy the class and I failed. He goes into the timer again.
Disconnected Code
private void Events_Disconnected(object sender, ClientDisconnectedEventArgs e)
{
classDictionary[e.IpPort].Dispose();
classDictionary.Remove(e.IpPort);
}
DataParse Code
public class DataParse : IDisposable
{
private bool _disposed = false;
private SafeHandle _safeHandle = new SafeFileHandle(IntPtr.Zero, true);
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (_disposed)
{
return;
}
if (disposing)
{
// Dispose managed state (managed objects).
_safeHandle?.Dispose();
}
_disposed = true;
}
Timer timer;
byte[] moduleBuffer;
int writePtr;
string key;
public void DataParseRun(string IpPort)
{
moduleBuffer = new byte[50000];
writePtr = 0;
timer = new Timer(new TimerCallback(ParseTimer), null, TimeSpan.FromMilliseconds(1000), TimeSpan.FromMilliseconds(200));
key = IpPort;
}
void ParseTimer(object state)
{
var abc = key;
}
}
How can I destroy the class.
Try manually disposing the timer in the Dispose method. As far as I see the timer is never disposed.
timer.Dispose();
EDIT: Cant comment yet so Ill edit the answer. As far as I am aware you cant manually just remove your instance from memory.
It will be collected via Garbage Collector once all references to the instance are lost or unreachable - thus once you, as Trix in his answer advises, remove the instance from the Dictionary and dispose of the Timer and SafeHandle there should be nothing stopping the GC from collecting it. However when exactly this happens isn't up to you.
EDIT2: I would say so. You can try to test it by reading some huge file to String to take up 100MB and watch if the memory is let go once you dispose of everything. Apparently there is also a direct call you can make to the GC: GC.Collect() - if you call it from class I don't think it will collect that class but for testing you can call it after you dispose from the dictionary.
This question already has answers here:
does nulling a System.Threading.Timer stop it?
(4 answers)
Closed 3 years ago.
Please see example below. Even though the reference to obj is set to null, the obj is not released and Obj_Elapsed continues printing i. Notice there is no reference to the timer out of the scope of the ObjectWithTimer constructor.
public class Program
{
public static void Main(string[] args)
{
object obj = new ObjectWithTimer();
Console.ReadLine();
Console.WriteLine("obj=null");
obj = null;
Console.ReadLine();
}
}
public class ObjectWithTimer
{
private int i;
public System.Timers.Timer t;
public ObjectWithTimer()
{
t = new System.Timers.Timer(5000);
t.Elapsed += Obj_Elapsed;
t.Enabled = true;
}
public void Obj_Elapsed(object sender, ElapsedEventArgs e)
{
i++;
Console.WriteLine(i);
}
}
Setting null in this instance and/or going out of scope is not good enough, The Timer has resources it's managing and needs to be cleaned up.
Since System.Timers.Timer Implements IDisposable, ideally so should your wrapper class
public class ObjectWithTimer : IDisposable
{
// Flag: Has Dispose already been called?
private bool _disposed = false;
private int _i;
public System.Timers.Timer Timer { get; }
public ObjectWithTimer()
{
Timer = new System.Timers.Timer(5000);
Timer.Elapsed += Obj_Elapsed;
Timer.Enabled = true;
}
public void Obj_Elapsed(object sender, ElapsedEventArgs e)
{
_i++;
Console.WriteLine(_i);
}
// Public implementation of Dispose pattern callable by consumers.
public void Dispose() =>Dispose(true);
// Protected implementation of Dispose pattern.
protected virtual void Dispose(bool disposing)
{
if (_disposed) return;
if (disposing) Timer?.Dispose();
_disposed = true;
}
}
You should in turn then also dispose of the wrapper called at some stage, and not just set it null, the easiest way to do that is with the using statement
Provides a convenient syntax that ensures the correct use of
IDisposable objects.
public static void Main(string[] args)
{
using(object obj = new ObjectWithTimer())
{
Console.ReadLine();
Console.WriteLine("obj=null");
}
Console.ReadLine();
}
Implementing a Dispose method
You implement a Dispose method to release unmanaged resources used by
your application. The .NET garbage collector does not allocate or
release unmanaged memory.
Note : This wasn't a complete tutorial on the IDisposable pattern, just an example. Please do your own research and diligence on this implementation
Additional Resouces
Do you need to dispose of objects and set them to null?
Why do we need Dispose() method on some object? Why doesn't the garbage collector do this work?
I have a class which starts a Task and want to ensure that the Task stops when the object is garbage collected.
I have implemented the IDisposable pattern to ensure that if the object is disposed manually or used within a using block, then the Task stops correctly. However, I cant guarantee that the end user will call Dispose() or use the object within a using block. I know that the Garbage Collector will eventually call the Finalizer - does this mean that the task is left running?
public class MyClass : IDisposable
{
private readonly CancellationTokenSource feedCancellationTokenSource =
new CancellationTokenSource();
private readonly Task feedTask;
public MyClass()
{
feedTask = Task.Factory.StartNew(() =>
{
while (!feedCancellationTokenSource.IsCancellationRequested)
{
// do finite work
}
});
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
feedCancellationTokenSource.Cancel();
feedTask.Wait();
feedCancellationTokenSource.Dispose();
feedTask.Dispose();
}
}
~MyClass()
{
Dispose(false);
}
}
It was suggested in this question to add a volatile bool which is set from the Finalizer and observed from the task. Is this recommended, or is there a better way to achieve what I need?
(I'm using .NET 4 hence the use of TaskFactory.StartNew rather than Task.Run)
EDIT:
To give some context to the question - which is not actually shown in the above code snippet: I am creating a Network client class which has a mechanism to keep alive by regularly sending packets to the server. I chose not to put all this detail in the example as it wasn't relevant to my specific question. However, what I actually want is the ability for the user to set a KeepAlive boolean property to true, which will start a task to send data to the server every 60 seconds. If the user sets the property to false then the task stops. IDisposable got me 90% of the way there, however it relies on the user disposing it properly (explicitly or via using). I don't want to expose keep alive tasks to the user for them to cancel explicitly, I just want a "simple" KeepAlive = true/false to start/stop the task AND I want the task to stop when the user is finished with the object - even if they don't dispose of it properly. I'm starting to think that this isn't possible!
I'll sketch an answer. I'm not 100% confident that this will work. Finalization is a complicated issue and I'm not proficient in it.
There can be no object reference from the task to whatever object is supposed to be finalized.
You can't touch other objects from a finalizer that are not known to be safe. The built-in .NET classes do not usually document this safety property. You can't rely on that (usually).
class CancellationFlag { public volatile bool IsSet; }
You can now share an instance of this class between the task and MyClass. The task must poll the flag and MyClass must set it.
In order to ensure that the task never accidentally references the outer object I'd structure the code like this:
Task.Factory.StartNew(TaskProc, state); //no lambda
static void TaskProc(object state) { //static
}
This way you can explicitly thread any state through state. This would, at least, be an instance of CancellationFlag but under no circumstances a reference to MyClass.
I created the program below to explore the differences...
From my observations with it, it looks like it makes no difference whether it's a cancellation token or a volatile bool, what really matters is that the Task.StartNew method isn't called using a lambda expression.
Edit: to clarify: if the lambda refers to a static method, it's actually fine: the problem comes when the lambda causes a reference to the containing class to be included: so either a reference to a member variable of the parent class or else a reference to an instance method of the parent class.
Please do give this a try and let me know if you come to the same conclusion.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApplication7
{
class Program
{
static void Main(string[] args)
{
Logger.LogFile = #"c:\temp\test\log.txt";
Task.Run(() =>
{
// two instances (not disposed properly)
// if left to run, this background task keeps running until the application exits
var c1 = new MyClassWithVolatileBoolCancellationFlag();
// if left to run, this background task cancels correctly
var c2 = new MyClassWithCancellationSourceAndNoLambda();
//
var c3 = new MyClassWithCancellationSourceAndUsingTaskDotRun();
//
var c4 = new MyClassWithCancellationSourceAndUsingTaskDotRunButNoParentReference();
}).GetAwaiter().GetResult();
// instances no longer referenced at this point
Logger.Log("Press Enter to exit");
Console.ReadLine(); // press enter to allow the console app to exit normally: finalizer gets called on both instances
}
static class Logger
{
private static object LogLock = new object();
public static string LogFile;
public static void Log(string toLog)
{
try
{
lock (LogLock)
using (var f = File.AppendText(LogFile))
f.WriteLine(toLog);
Console.WriteLine(toLog);
}
catch (Exception ex)
{
Console.WriteLine("Logging Exception: " + ex.ToString());
}
}
}
// finalizer gets called eventually (unless parent process is terminated)
public class MyClassWithCancellationSourceAndUsingTaskDotRunButNoParentReference : IDisposable
{
private CancellationTokenSource cts = new CancellationTokenSource();
private readonly Task feedTask;
public MyClassWithCancellationSourceAndUsingTaskDotRunButNoParentReference()
{
Logger.Log("New MyClassWithCancellationSourceAndUsingTaskDotRunButNoParentReference Instance");
var token = cts.Token; // NB: by extracting the struct here (instead of in the lambda in the next line), we avoid the parent reference (via the cts member variable)
feedTask = Task.Run(() => Background(token)); // token is a struct
}
private static void Background(CancellationToken token) // must be static or else a reference to the parent class is passed
{
int i = 0;
while (!token.IsCancellationRequested) // reference to cts means this class never gets finalized
{
Logger.Log("Background task for MyClassWithCancellationSourceAndUsingTaskDotRunButNoParentReference running. " + i++);
Thread.Sleep(1000);
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
cts.Cancel();
if (disposing)
{
feedTask.Wait();
feedTask.Dispose();
Logger.Log("MyClassWithCancellationSourceAndUsingTaskDotRunButNoParentReference Disposed");
}
else
{
Logger.Log("MyClassWithCancellationSourceAndUsingTaskDotRunButNoParentReference Finalized");
}
}
~MyClassWithCancellationSourceAndUsingTaskDotRunButNoParentReference()
{
Dispose(false);
}
}
// finalizer doesn't get called until the app is exiting: background process keeps running
public class MyClassWithCancellationSourceAndUsingTaskDotRun : IDisposable
{
private CancellationTokenSource cts = new CancellationTokenSource();
private readonly Task feedTask;
public MyClassWithCancellationSourceAndUsingTaskDotRun()
{
Logger.Log("New MyClassWithCancellationSourceAndUsingTaskDotRun Instance");
//feedTask = Task.Factory.StartNew(Background, cts.Token);
feedTask = Task.Run(() => Background());
}
private void Background()
{
int i = 0;
while (!cts.IsCancellationRequested) // reference to cts & not being static means this class never gets finalized
{
Logger.Log("Background task for MyClassWithCancellationSourceAndUsingTaskDotRun running. " + i++);
Thread.Sleep(1000);
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
cts.Cancel();
if (disposing)
{
feedTask.Wait();
feedTask.Dispose();
Logger.Log("MyClassWithCancellationSourceAndUsingTaskDotRun Disposed");
}
else
{
Logger.Log("MyClassWithCancellationSourceAndUsingTaskDotRun Finalized");
}
}
~MyClassWithCancellationSourceAndUsingTaskDotRun()
{
Dispose(false);
}
}
// finalizer gets called eventually (unless parent process is terminated)
public class MyClassWithCancellationSourceAndNoLambda : IDisposable
{
private CancellationTokenSource cts = new CancellationTokenSource();
private readonly Task feedTask;
public MyClassWithCancellationSourceAndNoLambda()
{
Logger.Log("New MyClassWithCancellationSourceAndNoLambda Instance");
feedTask = Task.Factory.StartNew(Background, cts.Token);
}
private static void Background(object state)
{
var cancelled = (CancellationToken)state;
if (cancelled != null)
{
int i = 0;
while (!cancelled.IsCancellationRequested)
{
Logger.Log("Background task for MyClassWithCancellationSourceAndNoLambda running. " + i++);
Thread.Sleep(1000);
}
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
cts.Cancel();
if (disposing)
{
feedTask.Wait();
feedTask.Dispose();
Logger.Log("MyClassWithCancellationSourceAndNoLambda Disposed");
}
else
{
Logger.Log("MyClassWithCancellationSourceAndNoLambda Finalized");
}
}
~MyClassWithCancellationSourceAndNoLambda()
{
Dispose(false);
}
}
// finalizer doesn't get called until the app is exiting: background process keeps running
public class MyClassWithVolatileBoolCancellationFlag : IDisposable
{
class CancellationFlag { public volatile bool IsSet; }
private CancellationFlag cf = new CancellationFlag();
private readonly Task feedTask;
public MyClassWithVolatileBoolCancellationFlag()
{
Logger.Log("New MyClassWithVolatileBoolCancellationFlag Instance");
feedTask = Task.Factory.StartNew(() =>
{
int i = 0;
while (!cf.IsSet)
{
Logger.Log("Background task for MyClassWithVolatileBoolCancellationFlag running. " + i++);
Thread.Sleep(1000);
}
});
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
cf.IsSet = true;
if (disposing)
{
feedTask.Wait();
feedTask.Dispose();
Logger.Log("MyClassWithVolatileBoolCancellationFlag Disposed");
}
else
{
Logger.Log("MyClassWithVolatileBoolCancellationFlag Finalized");
}
}
~MyClassWithVolatileBoolCancellationFlag()
{
Dispose(false);
}
}
}
}
Update:
Added a few more tests (now included above): and came to the same conclusion as "usr": the finalizer never gets called if there's a reference to the parent class (which makes sense: an active reference exists, therefore the GC doesn't kick in)
My question is simple, why GC can't figure it out that timer object in the main should be garbage collected along with the timer inside TestTimer and associated EventHandler?
Why am I continously getting console.Writeline output?
class Program
{
public static void Main()
{
TestTimer timer = new TestTimer();
timer = null;
GC.Collect();
GC.WaitForPendingFinalizers();
Console.ReadKey();
}
}
public class TestTimer
{
private Timer timer;
public TestTimer()
{
timer = new Timer(1000);
timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
timer.Start();
}
private void timer_Elapsed(Object sender, ElapsedEventArgs args)
{
Console.Write("\n" + DateTime.Now);
}
}
Don't depend on the GC, use the Dispose pattern to properly dispose the TestTimer (which then should dispose the Timer).
However, what happens is that the timer keeps itself alive by getting a GC handle on itself. Read this blog post:
http://nitoprograms.blogspot.com/2011/07/systemthreadingtimer-constructor-and.html?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+blogspot%2FOlZtT+%28Nito+Programming%29
Why do you expect that an active timer can get collected in the first place? My expectation is that it acts as a GC root. Else the timer would stop working just because you don't have a reference anymore.
You are not disposing the timer after use. This is what is delaying its collection.
If your class contains objects which implement IDisposable (like the Timer does), it should also implement IDisposable.
public class TestTimer : IDisposable
{
private Timer timer;
public TestTimer()
{
timer = new Timer(1000);
...
}
#region IDisposable
public void Dispose()
{
Dispose(true);
}
volatile bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (disposing && !disposed)
{
timer.Dispose();
GC.SupressFinalize(this);
disposed = true;
}
}
~TestTimer() { Dispose(false); }
#endregion
}
Your main method should then look like this:
public static void Main()
{
using (TestTimer timer = new TestTimer())
{
// do something
}
GC.Collect();
GC.WaitForPendingFinalizers();
Console.ReadKey();
}
Again, if your TestTimer is supposed to live longer than a scope of a single Main method, then the class which creates it and holds its reference should also implement IDisposable.
When you start a timer timer.Start() a new thread(s) will start at the background,
When you calling timer = null; you are not stopping the thread(s) that the timer used. The garbage collector will not kill or abort threads that are running no matter of the original object that create those threads.
It turns out that this state parameter (and the TimerCallback delegate) have an interesting effect on garbage collection: if neither of them reference the System.Threading.Timer object, it may be garbage collected, causing it to stop. This is because both the TimerCallback delegate and the state parameter are wrapped into a GCHandle. If neither of them reference the timer object, it may be eligible for GC, freeing the GCHandle from its finalizer.
See this thread for more details.
I've read several articles and posts that say that lock(this), lock(typeof(MyType)), lock("a string") are all bad practice because another thread could lock on the same key and cause a deadlock. In order to understand this problem, I was trying to create some sample code to illustrate the deadlock but have been unable to wrap my head around this.
Can someone write a concise bit of code that illustrates this classic problem? Please keep it short, I can digest code in smaller chunks only.
Edit:
I think lassevk sums it up well; that the real problem is that you have lost control over your locks. Once that happens, you cannot control the order the locks are called, and you are allowing a potential deadlock situation.
lock(this), lock(typeof(MyType)), etc all are situations where you have chosen a lock that is impossible to control.
A deadlock will only occur if you have more than one lock. You need a situation where both threads hold a resource that the other needs (which means there has to be a least two resources, and the two threads have to attempt to acquire them in a different order)
So a simple example:
// thread 1
lock(typeof(int)) {
Thread.Sleep(1000);
lock(typeof(float)) {
Console.WriteLine("Thread 1 got both locks");
}
}
// thread 2
lock(typeof(float)) {
Thread.Sleep(1000);
lock(typeof(int)) {
Console.WriteLine("Thread 2 got both locks");
}
}
Assuming both threads are started within a second of each others, they will both have time to grab the first lock before anyone gets to the inner lock. Without the Sleep() call, one of the threads would most likely have time to get and release both locks before the other thread even got started.
The idea is that you should never lock on something you cannot control who has access to.
Type objects are singletons visible to every .net piece of code and you cannot control who locks on your "this" object from the outside.
Same thing is for strings: since strings are immutable, the framework keeps just one instance of "hard coded" strings and puts them in a pool (the string is said to be interned), if you write two times in your code the string "hello", you will always get the same abject.
Consider the following example: you wrote just Thread1 in your super private call, while Thread2 is called by some library you are using in a background thread...
void Thread1()
{
lock (typeof(int))
{
Thread.Sleep(1000);
lock (typeof(long))
// do something
}
}
void Thread2()
{
lock (typeof(long))
{
Thread.Sleep(1000);
lock (typeof(int))
// do something
}
}
Sure, here you go.
Note that the common example for a deadlock is when you acquire multiple locks, and two or more threads end up waiting for each other.
For instance, two threads that locks like this:
Thread 1 Thread 2
Lock "A" Lock "B"
Lock "B" Lock "A" <-- both threads will stop dead here
waiting for the lock to be come
available.
However, in this example I didn't bother with that, I just let one thread lock indefinitely. You really don't want to loose control over your locks, so while this is a contrived example, the fact that the background thread can completely block the main thread like this, is bad.
using System;
using System.Threading;
namespace ConsoleApplication7
{
public class Program
{
public static void Main(string[] args)
{
LockableClass lockable = new LockableClass();
new Thread(new ParameterizedThreadStart(BackgroundMethod)).Start(lockable);
Thread.Sleep(500);
Console.Out.WriteLine("calling Reset");
lockable.Reset();
}
private static void BackgroundMethod(Object lockable)
{
lock (lockable)
{
Console.Out.WriteLine("background thread got lock now");
Thread.Sleep(Timeout.Infinite);
}
}
}
public class LockableClass
{
public Int32 Value1 { get; set; }
public Int32 Value2 { get; set; }
public void Reset()
{
Console.Out.WriteLine("attempting to lock on object");
lock (this)
{
Console.Out.WriteLine("main thread got lock now");
Value1 = 0;
Value2 = 0;
}
}
}
}
This is pretty standard bad-ness. Grabing the locks out of order and then sleeping with the lock. Two bad things to do. :)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace DeadLock
{
public class Program
{
static void Main(string[] args)
{
var ddt = new DontDoThat();
ddt.Go();
}
}
public class DontDoThat
{
private int _badSharedState = 0;
private readonly object _lock1 = new object();
private readonly object _lock2 = new object();
public void Go()
{
new Thread(BadGuy1).Start();
new Thread(BadGuy2).Start();
Console.WriteLine("Leaving Go!");
}
public void BadGuy1()
{
lock (_lock1)
{
Thread.Sleep(100); // yeild with the lock is bad
lock (_lock2)
{
_badSharedState++;
Console.Write("From Bad Guy #1: {0})", _badSharedState );
}
}
}
public void BadGuy2()
{
lock (_lock2)
{
lock (_lock1)
{
_badSharedState++;
Console.Write("From Bad Guy #2: {0})", _badSharedState);
}
}
}
}
}
The problem is that lock("a string") is locking on a singleton. This means that other objects that use the same lock could be an infinite wait.
for example:
using System;
using System.Threading;
namespace ThreadLock
{
class Program
{
static void Main(string[] args)
{
lock ("my lock")
{
ManualResetEvent evt = new ManualResetEvent(false);
WorkerObject worker = new WorkerObject(evt);
Thread t = new Thread(new ThreadStart(worker.Work));
t.Start();
evt.WaitOne();
}
}
}
class WorkerObject
{
private ManualResetEvent _evt;
public WorkerObject(ManualResetEvent evt)
{
_evt = evt;
}
public void Work()
{
lock ("my lock")
{
Console.WriteLine("worked.");
_evt.Set();
}
}
}
}
In this case, the calling code creates a lock on a string then makes a worker object. The worker object in Work() locks on the same string, which is a singleton in C#. It ends up in deadlock because the caller owns the lock and is waiting for a signal which will never come.
class Character
{
public Character Other;
public string Name;
private object locker = new object();
public Character(string name)
{
Name = name;
}
public void Go()
{
lock (locker)
{
Thread.Sleep(1000);
Console.WriteLine("go in {0}", Name);
Other.Go();
}
}
}
class Program
{
static void Main(string[] args)
{
Character a = new Character("A");
Character b = new Character("B");
a.Other = b;
b.Other = a;
new Thread(a.Go).Start();
b.Go();
Console.ReadLine();
}
}