Thread safe destructible event firing class in C# - c#

Recently, I was asked to implement a class as part of a selection process. I did the program as requested. However, I failed in the test. I am really curious to know what is wrong in my solution. Any help is much appreciated. The question and my solution are given below
Question:
Implement a thread safe class which fires an event every second from construction. There need to be a function for finding the seconds elapsed. This class has to implement IDisposable and any calls to seconds elapsed function after calling dispose should fail.
My solution:
namespace TimeCounter
{
public delegate void SecondsElapsedHandler(object o, EventArgs e);
/// <summary>
/// Summary description for SecondCounter
/// </summary>
public class SecondCounter : IDisposable
{
private volatile int nSecondsElapsed;
Timer myTimer;
private readonly object EventLock = new object();
private SecondsElapsedHandler secondsHandler;
public SecondCounter()
{
nSecondsElapsed = 0;
myTimer = new Timer();
myTimer.Elapsed += new ElapsedEventHandler(OneSecondElapsed);
myTimer.Interval = 1000;
myTimer.AutoReset = false;
myTimer.Start();
}
public void OneSecondElapsed(object source, ElapsedEventArgs e)
{
try
{
SecondsElapsedHandler handlerCopy;
lock (EventLock)
{
handlerCopy = secondsHandler;
nSecondsElapsed++;
}
if (secondsHandler != null)
{
secondsHandler(this, e);
}
}
catch (Exception exp)
{
Console.WriteLine("Exception thrown from SecondCounter OneSecondElapsed " + exp.Message);
}
finally
{
if (myTimer != null)
{
myTimer.Enabled = true;
}
}
}
public event SecondsElapsedHandler AnotherSecondElapsed
{
add
{
lock (EventLock)
{
secondsHandler += value;
}
}
remove
{
lock (EventLock)
{
secondsHandler -= value;
}
}
}
public int SecondsElapsed()
{
if (this.IsDisposed)
{
throw new ObjectDisposedException("SecondCounter");
}
return nSecondsElapsed;
}
private bool IsDisposed = false;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool Disposing)
{
if (!IsDisposed)
{
if (Disposing)
{
}
if (myTimer != null)
{
myTimer.Dispose();
}
}
secondsHandler = null;
IsDisposed = true;
}
~SecondCounter()
{
Dispose(false);
}
}
}

There are a few problems:
You might have been penalized for general Exception swallowing though that's not specifically related to threading issues.
There's a race condition on your timer.Dispose, as you could Dispose the timer before it is set Enabled again, resulting in an Exception.
You never set myTimer to null in Dispose.
You're accessing the managed class myTimer from the finalizer (disposing=false), which is a bad idea.
The explicit implementation of the event with locking is unnecessary. Delegates are immutable and adding/removing an event will never result in an invalid delegate state, though there can be race conditions if delegates are added/removed around the same time that the callback is fired. If you use the standard 'public event' declaration without an explicit backing private delegate, the synchronization will be handled automatically.
(minor point) If you're implementing the full Dispose pattern, it's customary to mark the Dispose(bool disposing) method as protected virtual, so that deriving classes can hook into the disposal mechanism. Better yet, mark your class sealed and you can eliminate the finalizer entirely.

Your finalizer is probably broken. It correctly passes false as the Disposing parameter. This should tell Dispose(bool) to avoid attempting to dispose other managed objects. But in that method you put:
if (Disposing)
{
}
if (myTimer != null)
{
myTimer.Dispose();
}
So you ignore the value of Disposing. This means that you call the timer's Dispose method from the finalizer thread, when that object may already have been finalized (if it has a finalizer, which it probably does). Finalizers run in an unpredictable order. It's generally recommended to not make calls to other GC-managed objects from a finalizer.
In fact, it's usually recommended that you don't write finalizers at all these days. The question didn't ask you to write one! It's unfortunate that most tutorials about IDisposable also talk about finalizers. They're different subjects.
You also catch Exception, the universal exception base class. This means you catch things like NullReferenceException. Not usually a good idea. You also log to the console, which is not worth much in a GUI or server-based application.
You can replace:
myTimer.Elapsed += new ElapsedEventHandler(OneSecondElapsed);
with:
myTimer.Elapsed += OneSecondElapsed;
Your variable naming is inconsistent. Refer to the Microsoft guidelines.

Related

Dispose the Class

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.

Object not released without reference to the timer Framework 4.8 [duplicate]

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?

Release PowerPoint Interop Com class member instance in C#

I create a simple addIn for Power point and this is the code
pp.Application ppApplication = new pp.Application();
private void Ribbon1_Load(object sender, RibbonUIEventArgs e)
{
ppApplication.PresentationOpen += new pp.EApplication_PresentationOpenEventHandler(ppApplication_PresentationOpen);
ppApplication.PresentationClose += new pp.EApplication_PresentationCloseEventHandler(ppApplication_PresentationClose);
}
void ppApplication_PresentationOpen(pp.Presentation Pres)
{
}
void ppApplication_PresentationClose(pp.Presentation Pres)
{
GC.Collect();
GC.WaitForPendingFinalizers();
Marshal.FinalReleaseComObject(ppApplication);
}
Power point never close if ppApplication is global. I think global com object dose not release in this way. What should I do?
Following the recommendation in this post Proper way of releasing COM objects?
1) Declare & instantiate COM objects at the last moment possible.
2) ReleaseComObject(obj) for ALL objects, at the soonest moment possible.
3) Always ReleaseComObject in the opposite order of creation.
4) NEVER call GC.Collect() except when required for debugging.
You should call
pp.Application ppApplication = new pp.Application();
within Ribbon_Load
Also you are asymmetric in your COM Instantiation and Release - you instantiate on class initialize (i.e. as a = new() in the variable declaration) but release when the presentation is closed. Closing a presentation isn't the same as closing the application - the ribbon is probably still available, and this will come to bite you.
The last point is that you never unhook the events you've hooked into the COM object, you should at least be doing
ppApplication.PresentationOpen -= new pp.EApplication_PresentationOpenEventHandler(ppApplication_PresentationOpen);
ppApplication.PresentationClose -= new pp.EApplication_PresentationCloseEventHandler(ppApplication_PresentationClose);
to deallocate the event handlers, otherwise you have some undead references.
You should apply Dispose/Finalize pattern to free you unmanaged resource properly. This will guarantee that once your class will be disposed, all unmanaged class members (not global variables) would be released.
See https://msdn.microsoft.com/en-us/library/b1yfkh5e(v=vs.100).aspx
using System;
using System.Runtime.InteropServices;
namespace PowerPointTestApp
{
class Program
{
static void Main(string[] args)
{
using (Container c = new Container())
{
Console.WriteLine("Opened..");
}
Console.WriteLine("Closed..");
}
}
public class Container: IDisposable
{
Microsoft.Office.Interop.PowerPoint.Application pp = new Microsoft.Office.Interop.PowerPoint.Application();
public Container()
{
pp.PresentationOpen += (pres)=>
{
//DoSomething
};
pp.Visible = Microsoft.Office.Core.MsoTriState.msoTrue;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
pp.Quit();
Marshal.FinalReleaseComObject(pp);
}
}
~Container()
{
Dispose(false);
}
}
}

How to handle processing real-time events that fire before processing of previous event is complete (C#)

Suppose we have a listener to a real-time event that executes some block of code upon the event being triggered.
for our discussion lets say we have a MyTime class, that has a member currentTime.
we have set it up so that whenever the computer clock changes, the currentTime is set to the value of current time.
We've implemented the property changed INotifyPropertyChanged interface for our currentTime object:
public event PropertyChangedEventHandler PropertyChanged;
public string currentTime
{
get { return _currentTime; }
set { _currentTime= value; this.NotifyPropertyChanged("currentTime"); }
}
public void NotifyPropertyChanged(object sender, PropertyChangedEventArgs e) {
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
Some other class, say ProcessTime is listening to this event:
TimeChanged += new PropertyChangedEventHandler(PropertyChanged};
and it has a function that will execute something:
public void TimeChanged(object sender, PropertyChangedEventArgs e)
{
// Process lots of calculations
}
Since our computer clock changes all the time, it will keep firing the event.
In my understanding, once the first time change occurs, we will execute the TimeChanged block. While we are executing, we will keep getting more and more notifications and processing them as fast as we can, creating a long queue of events still to be processed.
The problem is that after we process the first time change and move on to the next time change, the "real time" is already far ahead, and whatever we are calculating we are calculating for something that happened in the past.
What we would like to do is to ignore all new events until we finish our original processing, and only then start listening again for the event.
Setting up multiple threads is not an option as it doesn't address the issue, and we do not want to process every time change, only those when our resources have been freed up.
Obviously I've used the time change and the above code as a demonstrative example, but it demonstrates concisely and adequately (IMHO) what we are trying to accomplish here.
I would imagine to use some kind of buffer, but my knowledge here is very very limited.
Thanks
Thanks for all the answers so far. Will start on implementing it. Will try to document successes / failures.
Well, first the event in question is not being called asynchronously. So Unless you're setting the time on constantly changing threads, the call to set the time won't come back and you won't set it again until all of the events have handled it. If you want to prevent this problem, you need to move event handling to a different thread.
Ultimately the complexity of the situation and exactly how real-time you want to be can dictate the ultimate answer to this. But, assuming you want something that's fairly robust for a relatively few number of threads (let's say a dozen), here's roughly how I'd go about doing this.
private var _Callbacks = new List<PropertyChangedEventHandler>();
public event PropertyChangedEventHandler PropertyChanged
{
add
{
lock(_Callbacks)
_Callbacks.Add(value);
Thread Worker = new Thread(PollTime);
Worker.Background = true;
Worker.Start(value);
}
remove
{
lock(_Callbacks)
_Callbacks.Remove(value);
}
}
private void PollTime(object callback)
{
PropertyChangedEventHandler c = (PropertyChangedEventHandler)callback;
string LastReported = null;
while(true)
{
lock(_Callbacks)
if (!_Callbacks.Contains(c))
return;
if (LastReported != _currentTime)
{
LastReported = _currentTime;
c(this, new PropertyChangedEventArgs(name));
}
else
Thread.Sleep(10);
}
}
public string currentTime
{
get { return _currentTime; }
set { _currentTime= value; }
}
With that you get thread safety on your events (in case someone tries to subscribe/unsubscribe from them at an inopportune time), and each subscriber gets it's own thread to handle callbacks. The subscribers won't get all the same events, but they will all be notified when the time changes. Slower ones just won't get as many events because they'll lose some of the intermediate values. This won't notify if the time is reset with no change, but I don't see that as much of a loss. You may see problems if values alternate within a limited set, but with time that's not a problem.
For more reading on delegates, events and how they work, there's a very long, but very good piece at http://www.sellsbrothers.com/writing/delegates.htm
This would be my approach.
Do not let the consumer block the producer's event thread.
Create a lightweight "critical section" (basically an atomic condition variable) so that only one invocation of a consumer handler can be active at a given time.
Here is a complete example which implements this logic. There is an EventProducer and an EventConsumer. They can be configured to be faster or slower than each other as needed. The event producer creates a background thread to raise events. The EventConsumer uses a custom CriticalSectionSlim class with a simple TryEnter/Exit pattern to avoid simultaneous invocations of the handling code. It also posts the handling code to the thread pool using the default behavior of the .NET 4.0 Task class. If an exception occurs, it is rethrown from the main handler thread on the next invocation.
using System;
using System.Globalization;
using System.Threading;
using System.Threading.Tasks;
internal sealed class Program
{
private static void Main(string[] args)
{
using (EventProducer producer = new EventProducer(TimeSpan.FromMilliseconds(250.0d)))
using (EventConsumer consumer = new EventConsumer(producer, TimeSpan.FromSeconds(1.0d)))
{
Console.WriteLine("Press ENTER to stop.");
Console.ReadLine();
}
Console.WriteLine("Done.");
}
private static class ConsoleLogger
{
public static void WriteLine(string message)
{
Console.WriteLine(
"[{0}]({1}) {2}",
DateTime.Now.ToString("hh:mm:ss.fff", CultureInfo.InvariantCulture),
Thread.CurrentThread.ManagedThreadId,
message);
}
}
private sealed class EventConsumer : IDisposable
{
private readonly CriticalSectionSlim criticalSection;
private readonly EventProducer producer;
private readonly TimeSpan processingTime;
private Task currentTask;
public EventConsumer(EventProducer producer, TimeSpan processingTime)
{
if (producer == null)
{
throw new ArgumentNullException("producer");
}
if (processingTime < TimeSpan.Zero)
{
throw new ArgumentOutOfRangeException("processingTime");
}
this.processingTime = processingTime;
this.criticalSection = new CriticalSectionSlim();
this.producer = producer;
this.producer.SomethingHappened += this.OnSomethingHappened;
}
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (disposing)
{
this.producer.SomethingHappened -= this.OnSomethingHappened;
}
}
private void OnSomethingHappened(object sender, EventArgs e)
{
if (this.criticalSection.TryEnter())
{
try
{
this.StartTask();
}
catch (Exception)
{
this.criticalSection.Exit();
throw;
}
}
}
private void StartTask()
{
if (this.currentTask != null)
{
this.currentTask.Wait();
}
this.currentTask = Task.Factory.StartNew(this.OnSomethingHappenedTask);
}
private void OnSomethingHappenedTask()
{
try
{
this.OnSomethingHappenedImpl();
}
finally
{
this.criticalSection.Exit();
}
}
private void OnSomethingHappenedImpl()
{
ConsoleLogger.WriteLine("BEGIN: Consumer processing.");
Thread.CurrentThread.Join(this.processingTime);
ConsoleLogger.WriteLine("END: Consumer processing.");
}
}
private sealed class EventProducer : IDisposable
{
private readonly TimeSpan timeBetweenEvents;
private readonly Thread thread;
private volatile bool shouldStop;
public EventProducer(TimeSpan timeBetweenEvents)
{
if (timeBetweenEvents < TimeSpan.Zero)
{
throw new ArgumentOutOfRangeException("timeBetweenEvents");
}
this.timeBetweenEvents = timeBetweenEvents;
this.thread = new Thread(this.Run);
this.thread.Start();
}
public event EventHandler SomethingHappened;
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (disposing)
{
this.shouldStop = true;
this.thread.Join();
}
}
private void Run()
{
while (!shouldStop)
{
this.RaiseEvent();
Thread.CurrentThread.Join(this.timeBetweenEvents);
}
}
private void RaiseEvent()
{
EventHandler handler = this.SomethingHappened;
if (handler != null)
{
ConsoleLogger.WriteLine("Producer is raising event.");
handler(this, EventArgs.Empty);
}
}
}
private sealed class CriticalSectionSlim
{
private int active;
public CriticalSectionSlim()
{
}
public bool TryEnter()
{
return Interlocked.CompareExchange(ref this.active, 1, 0) == 0;
}
public void Exit()
{
Interlocked.Exchange(ref this.active, 0);
}
}
}
Well you can do something like this
as soon as you receive the event, unregister the event or in other words stop listening to event anymore.
Once you are done with your event processing start listening to event again by re-registering to event
public void TimeChanged(object sender, PropertyChangedEventArgs e)
{
//un register
TimeChanged -= new PropertyChangedEventHandler(PropertyChanged};
// Process lots of calculations
//re-register
TimeChanged += new PropertyChangedEventHandler(PropertyChanged};
}
I suggest that all scheduled tasks be placed in a queue ordered by process time (DateTime). The time event (tick) only needs to check the if the task at the head of the queue is 'pending'. That is if its time to process has been reached or passed. Then that task is removed from the queue, given the current time, and executed.
The task notifies the task queue when it has finished by a call back given in the execute method (that presumably also took current time). The task queue will not execute any other tasks while a task is executing. When a task notifies completion the task queue will immediately check if the task, if any, at the head of the queue is pending and so on.
Now a nice refinement that can be done here when u have time ordered task queue is that instead of periodic ticks you set a timer to fire (or one time changed listener) when it is time to execute the task at the head of the queue as you always know the time to next event. No need to multiple listeners and one controller for how many are executing, etc.
interface ITask
{
void Execute(ITaskCallBack callBack, DateTime currentTime);
}
interface ITaskCallBack
{
void OnCompleted(ITask task); // The task parameter is needed for concurrency
}
Whenever a task is added or deleted the time to next event is updated.
Important: If you add a new task that happens to wants to execute at the same time as an existing task you should add it after all tasks for the same time. This avoids child tasks hogging the scheduler.
The timed queue is your task scheduler/controller. You can make it single threaded or multi threaded as you like. Although I do not see much point in multi threading unless your using multiple processors.
interface ITaskScheduler
{
void Add(ITask task, DateTime executeTime);
void Remove(ITask);
}
Another nice spin off here is that the scheduler knows the time scheduled and the time actually started. Hence you have valuable diagnostic for delayed tasks or latencies due to loading. Important if you system needs to performance deterministic.
Hope this makes sense and is useful.
Best regards

Why can't GC figure it out?

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.

Categories

Resources