Only raise an event if the previous one was completed - c#

I'm using a System.Timers.Timer in my application. Every second I run a function which does some job. The thing is, this function can block for some little time (it reads then processes a large file from disk). I want to start that function only if its previous "execution instance" has completed. I thought I could achieve this with a Mutex:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Timers;
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
static Mutex TimerMut = new Mutex(false);
public static void Main()
{
Thread TT = new Thread(new ThreadStart(delegate()
{
System.Timers.Timer oTimer = new System.Timers.Timer();
oTimer.Elapsed += new ElapsedEventHandler(Handler);
oTimer.Interval = 1000;
oTimer.Enabled = true;
}));
TT.Start();
Console.Read();
}
private static void Handler(object oSource,
ElapsedEventArgs oElapsedEventArgs)
{
TimerMut.WaitOne();
Console.WriteLine("foo");
Thread.Sleep(500); //simulate some work
Console.WriteLine("bar");
TimerMut.ReleaseMutex();
}
}
}
That doesn't work, "foos" still appear every second. How can I achieve this?
EDIT: You're right, it makes no sense to start a new thread to handle this. I thought only System.Threading.Timer is launched in a separate thread.

I'm not sure why you are using a new thread to start the timer, since timers run on their own thread, but here's a method that works. Simply turn the timer off until you are done with the current interval.
static System.Timers.Timer oTimer
public static void Main()
{
oTimer = new System.Timers.Timer();
oTimer.Elapsed += new ElapsedEventHandler(Handler);
oTimer.Interval = 1000;
oTimer.Enabled = true;
}
private void Handler(object oSource, ElapsedEventArgs oElapsedEventArgs)
{
oTimer.Enabled = false;
Console.WriteLine("foo");
Thread.Sleep(5000); //simulate some work
Console.WriteLine("bar");
oTimer.Enabled = true;
}

If you want to skip the tick if another is already working you can do this.
private readonly object padlock = new object();
private void SomeMethod()
{
if(!Monitor.TryEnter(padlock))
return;
try
{
//Do heavy work
}
finally
{
Monitor.Exit(padlock);
}
}

Easiest way I know of to do this kind of thing:
internal static volatile bool isRunning;
public static void Main()
{
Thread TT = new Thread(new ThreadStart(delegate()
{
System.Timers.Timer oTimer = new System.Timers.Timer();
oTimer.Elapsed += new ElapsedEventHandler(Handler);
oTimer.Interval = 1000;
oTimer.Enabled = true;
}));
TT.Start();
}
private void Handler(object oSource,
ElapsedEventArgs oElapsedEventArgs)
{
if(isRunning) return;
isRunning = true;
try
{
Console.WriteLine("foo");
Thread.Sleep(500); //simulate some work
Console.WriteLine("bar");
}
finally { isRunning = false; }
}
The handler still runs, but the very first thing it does is make sure that another handler isn't running, and if one is, it stops immediately.
For timers executing handlers more quickly (like 3-4 times a second), this has the possibility to race; two threads could proceed past the guard clause before one of them sets the bit. You can avoid this with a couple of lock statements, similar to a Mutex or Monitor:
static object syncObj = new object();
private void Handler(object oSource,
ElapsedEventArgs oElapsedEventArgs)
{
lock(syncObj)
{
if(isRunning) return;
isRunning = true;
}
try
{
Console.WriteLine("foo");
Thread.Sleep(500); //simulate some work
Console.WriteLine("bar");
}
finally { lock(syncObj) { isRunning = false; } }
}
This will ensure that only one thread can ever be examining or modifying isRunning, and as isRunning is marked volatile, the CLR won't cache its value as part of each thread's state for performance; each thread has to look at exactly the same memory location to examine or change the value.

You can follow the following pattern to skip doing the indicated work if another invocation of this method is still running:
private int isWorking = 0;
public void Foo()
{
if (Interlocked.Exchange(ref isWorking, 1) == 0)
{
try
{
//Do work
}
finally
{
Interlocked.Exchange(ref isWorking, 0);
}
}
}
The approach that you were using with a Mutex will result in addition ticks waiting for earlier ticks to finish, not skipping invocations when another is still running, which is what you said you wanted. (When dealing with timers like this its common to want to skip such ticks, not wait. If your tick handlers regularly take too long you end up with a giant queue of waiting handlers.)

Related

Halting program execution until a timer stops

I want to produce some text in a console window for a certain amount of time before clearing it and showing more text. I thought the following code would do that, but instead, after the timer expires, the console is cleared but no other text appears.
Is this the correct way to halt program execution until a timer expires?
static void Main (string [] args)
{
const int PEEK_TIME = 5;
const int SECOND = 1000;
Timer peekTimer = new Timer (SECOND * PEEK_TIME);
peekTimer.Elapsed += onTimerTick;
peekTimer.AutoReset = false;
peekTimer.Start ();
Console.WriteLine ("Timer started...");
while (peekTimer.Enabled) { }
Console.WriteLine ("Timer done.");
Console.ReadLine ();
}
static void onTimerTick (Object source, System.Timers.ElapsedEventArgs e)
{
Console.Clear ();
}
Here is codesample using the Thread.Sleep function.
using System;
using System.Threading;
namespace ConsoleApplication
{
public class Program
{
public static void Main()
{
Console.WriteLine("Timer Start!");
Thread.Sleep(5000);
Console.Clear();
Console.WriteLine("End");
Console.ReadKey();
}
}
}
You don't need timer for this:
static void Main (string [] args)
{
const int PEEK_TIME = 5;
const int SECOND = 1000;
var task = Task.Run(()=>
{
Console.WriteLine ("Work started...");
Thread.Sleep(PEEK_TIME*SECOND);
Console.Clear();
});
task.Wait();
Console.WriteLine ("Work done.");
Console.ReadLine ();
}
In your onTimerTick event, you need to stop the timer (or set peekTimer.Enabled == false) if you want the while loop to exit:
static void onTimerTick (Object source, System.Timers.ElapsedEventArgs e)
{
Console.Clear ();
peekTimer.Stop();
}
In order to do this, you'll have to declare the timer at a wider scope so you can access it from your Main method and from the Tick event handler:
namespace ConsoleApplication
{
timer peekTimer;
public class Program
{
In answer to your larger question, this is not the best way to do it. If you're just going to sit and do nothing for a specific amount of time, you might as well just put the thread to sleep rather than spinning around the whole time:
Console.WriteLine("Waiting 5 seconds...");
Thread.Sleep(TimeSpan.FromSeconds(5));
Console.WriteLine("...Time's up!!");
In my game I use this approach:
public static Timer peekTimer = new Timer (SECOND * PEEK_TIME);
static void Main (string [] args)
{
const int PEEK_TIME = 5;
const int SECOND = 1000;
Console.WriteLine ("Timer started...");
peekTimer.Interval = new TimeSpan(0, 0, 0, 0, SECOND * PEEK_TIME);
peekTimer.Tick += new EventHandler(onTimerTick);
peekTimer.Start();
}
static void onTimerTick (Object source, System.Timers.ElapsedEventArgs e)
{
peekTimer.Stop();
Console.Clear ();
Console.WriteLine ("Timer done.");
Console.ReadLine ();
}

Can't create a timer that runs a function in C#

this time I come to you guys asking for help with Timers (System.Timers to be specific, I believe)
I need to make a timer that runs a function every second, so far this is what I've got:
public class Game1 : Microsoft.Xna.Framework.Game
{
Timer CooldownTracker;
protected override void LoadContent()
{
CooldownTracker = new Timer();
CooldownTracker.Interval = 1000;
CooldownTracker.Start();
}
private void DecreaseCooldown(List<Brick> bricks)
{
foreach (Brick brick in bricks)
{
if (brick.Cooldown == 0)
brick.Cooldown = 2;
else
brick.Cooldown--;
}
}
}
...How do I make the timer run the DecreasedCooldown(List bricks) function? I've tried with Timer.Elapsed but I get nothing, I can't pass down the arguments that way. Any ideas?
Thanks!
You need to attach a Timer Elapsed event like:
CooldownTracker = new Timer();
CooldownTracker.Elapsed += CooldownTracker_Elapsed; //HERE
CooldownTracker.Interval = 1000;
CooldownTracker.Start();
and then the event:
void CooldownTracker_Elapsed(object sender, ElapsedEventArgs e)
{
DecreaseCooldown(yourList);
}
You can use Thread if you want. It's not so accurate maybe cause of ThreadPool but can help.
Like
private bool run = true;
Thread timer = new Thread(Run);
timer.Start();
And define Run
private void Run()
{
while(run)
{
// Call function
Thread.Sleep(1000); //Time in millis
}
}
if you get cross-thread exception try to use for loop instead of foreach or lock your resources.

Make sure all threads exited

In a win form application, I have an array of threads which are started like this:
bool stop = false;
Thread[] threads = new Thread[10];
for (int i = 0; i < threads.Length; i++)
threads[i] = new Thread(new ThreadStart(Job));
// How to make sure all threads have exited, when the boolean = false
void Job()
{
while (!stop)
// Do something
}
Now if user press STOP, the boolean value for stop will set to true, so threads exit the Job method one after another. How can I make sure all threads are exited?
NOTE: I need traditional threading for my case and TaskLibrary doesn't fit my scenario.
Use the Join method to check if all threads have stopped.
foreach (var t in threads)
{
t.Join();
}
Have you thought about using BackgroundWorkers instead? You said "traditional threads"..I'm not exactly sure what you mean so I don't know if this is a valid proposal or not, but here it is anyways in case Join() doesn't solve your problem
BackgroundWorker[] workers = new BackgroundWorker[10];
bool allThreadsDone = false;
// initialize BackgroundWorkers
for (int i = 0; i < 10; i++)
{
workers[i] = new BackgroundWorker();
workers[i].WorkerSupportsCancellation = true;
workers[i].RunWorkerCompleted +=
new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
workers[i].DoWork += new DoWorkEventHandler(AlgorithmsUI_DoWork);
workers[i].RunWorkerAsync();
}
// thread entry point..DoWork is fired when RunWorkerAsync is called
void AlgorithmsUI_DoWork(object sender, DoWorkEventArgs e)
{
while (!stop)
// do something
}
// this event is fired when the BGW finishes execution
private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
bool threadsStillRunning = false;
foreach (BackgroundWorker worker in workers)
{
if (worker.IsBusy)
{
threadsStillRunning = true;
break;
}
}
if (!threadsStillRunning)
allThreadsDone = true;
}
protected override OnFormClosing(FormClosingEventArgs e)
{
if (!allThreadsDone)
{
e.Cancel = true;
MessageaBox.Show("Threads still running!");
}
}
This should prevent your form from closing if any threads are still running.
I'm not sure if this is what you're looking for, but here's a simple solution I used back in .NET 3.0 to make sure a large but deterministic number of threads had completed before continuing:
Global:
AutoResetEvent threadPoolComplete = new AutoResetEvent(false);
static int numThreadsToRun;
As you activate the threads:
numThreadsToRun = [number of threads];
[start your threads];
threadPoolComplete.WaitOne();
At the end of each thread's code:
if (Interlocked.Decrement(ref numThreadsToRun) == 0)
{
threadPoolComplete.Set();
}

Pause/Resume thread whith AutoResetEvent

In this code I want to Pause/Resume a thread using an AutoResetEvent and a bool variable.
Is is possible to Pause whithout testing each time (in for loop of Work()) if blocked==true?
Testing of "blocked" variable needs locking also and i think this is time consuming.
class MyClass
{
AutoResetEvent wait_handle = new AutoResetEvent();
bool blocked = false;
void Start()
{
Thread thread = new Thread(Work);
thread.Start();
}
void Pause()
{
blocked = true;
}
void Resume()
{
blocked = false;
wait_handle.Set();
}
private void Work()
{
for(int i = 0; i < 1000000; i++)
{
if(blocked)
wait_handle.WaitOne();
Console.WriteLine(i);
}
}
}
Yes, you can avoid the test you are performing by using a ManualResetEvent.
The ManualResetEvent will let your thread pass as long as it is "set" (signalled), but unlike the AutoResetEvent you had previously, it doesn't automatically reset as a thread passes it. This means you can leave it Set to allow work in your loop, and can Reset it to pause:
class MyClass
{
// set the reset event to be signalled initially, thus allowing work until pause is called.
ManualResetEvent wait_handle = new ManualResetEvent (true);
void Start()
{
Thread thread = new Thread(Work);
thread.Start();
}
void Pause()
{
wait_handle.Reset();
}
void Resume()
{
wait_handle.Set();
}
private void Work()
{
for(int i = 0; i < 1000000; i++)
{
// as long as this wait handle is set, this loop will execute.
// as soon as it is reset, the loop will stop executing and block here.
wait_handle.WaitOne();
Console.WriteLine(i);
}
}
}

Memory leak while using Threads

I appear to have a memory leak in this piece of code. It is a console app, which creates a couple of classes (WorkerThread), each of which writes to the console at specified intervals. The Threading.Timer is used to do this, hence writing to the console is performed in a separate thread (the TimerCallback is called in a seperate thread taken from the ThreadPool). To complicate matters, the MainThread class hooks on to the Changed event of the FileSystemWatcher; when the test.xml file changes, the WorkerThread classes are recreated.
Each time the file is saved, (each time that the WorkerThread and therefore the Timer is recreated), the memory in the Task Manager increases (Mem Usage, and sometimes also VM Size); furthermore, in .Net Memory Profiler (v3.1), the Undisposed Instances of the WorkerThread class increases by two (this may be a red herring though, because I've read that .Net Memory Profiler had a bug whereby it struggled to detect disposed classes.
Anyway, here's the code - does anyone know what's wrong?
EDIT: I've moved the class creation out of the FileSystemWatcher.Changed event handler, meaning that the WorkerThread classes are always being created in the same thread. I've added some protection to the static variables. I've also provided threading information to show more clearly what's going on, and have been interchanging using the Timer with using an explicit Thread; however, the memory is still leaking! The Mem Usage increases slowly all the time (is this simply due to extra text in the console window?), and the VM Size increases when I change the file. Here is the latest version of the code:
EDIT This appears to be primarily a problem with the console using up memory, as you write to it. There is still a problem with explicitly written Threads increasing the memory usage. See my answer below.
class Program
{
private static List<WorkerThread> threads = new List<WorkerThread>();
static void Main(string[] args)
{
MainThread.Start();
}
}
public class MainThread
{
private static int _eventsRaised = 0;
private static int _eventsRespondedTo = 0;
private static bool _reload = false;
private static readonly object _reloadLock = new object();
//to do something once in handler, though
//this code would go in onStart in a windows service.
public static void Start()
{
WorkerThread thread1 = null;
WorkerThread thread2 = null;
Console.WriteLine("Start: thread " + Thread.CurrentThread.ManagedThreadId);
//watch config
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = "../../";
watcher.Filter = "test.xml";
watcher.EnableRaisingEvents = true;
//subscribe to changed event. note that this event can be raised a number of times for each save of the file.
watcher.Changed += (sender, args) => FileChanged(sender, args);
thread1 = new WorkerThread("foo", 10);
thread2 = new WorkerThread("bar", 15);
while (true)
{
if (_reload)
{
//create our two threads.
Console.WriteLine("Start - reload: thread " + Thread.CurrentThread.ManagedThreadId);
//wait, to enable other file changed events to pass
Console.WriteLine("Start - waiting: thread " + Thread.CurrentThread.ManagedThreadId);
thread1.Dispose();
thread2.Dispose();
Thread.Sleep(3000); //each thread lasts 0.5 seconds, so 3 seconds should be plenty to wait for the
//LoadData function to complete.
Monitor.Enter(_reloadLock);
thread1 = new WorkerThread("foo", 10);
thread2 = new WorkerThread("bar", 15);
_reload = false;
Monitor.Exit(_reloadLock);
}
}
}
//this event handler is called in a separate thread to Start()
static void FileChanged(object source, FileSystemEventArgs e)
{
Monitor.Enter(_reloadLock);
_eventsRaised += 1;
//if it was more than a second since the last event (ie, it's a new save), then wait for 3 seconds (to avoid
//multiple events for the same file save) before processing
if (!_reload)
{
Console.WriteLine("FileChanged: thread " + Thread.CurrentThread.ManagedThreadId);
_eventsRespondedTo += 1;
Console.WriteLine("FileChanged. Handled event {0} of {1}.", _eventsRespondedTo, _eventsRaised);
//tell main thread to restart threads
_reload = true;
}
Monitor.Exit(_reloadLock);
}
}
public class WorkerThread : IDisposable
{
private System.Threading.Timer timer; //the timer exists in its own separate thread pool thread.
private string _name = string.Empty;
private int _interval = 0; //thread wait interval in ms.
private Thread _thread = null;
private ThreadStart _job = null;
public WorkerThread(string name, int interval)
{
Console.WriteLine("WorkerThread: thread " + Thread.CurrentThread.ManagedThreadId);
_name = name;
_interval = interval * 1000;
_job = new ThreadStart(LoadData);
_thread = new Thread(_job);
_thread.Start();
//timer = new Timer(Tick, null, 1000, interval * 1000);
}
//this delegate instance does NOT run in the same thread as the thread that created the timer. It runs in its own
//thread, taken from the ThreadPool. Hence, no need to create a new thread for the LoadData method.
private void Tick(object state)
{
//LoadData();
}
//Loads the data. Called from separate thread. Lasts 0.5 seconds.
//
//private void LoadData(object state)
private void LoadData()
{
while (true)
{
for (int i = 0; i < 10; i++)
{
Console.WriteLine(string.Format("Worker thread {0} ({2}): {1}", _name, i, Thread.CurrentThread.ManagedThreadId));
Thread.Sleep(50);
}
Thread.Sleep(_interval);
}
}
public void Stop()
{
Console.WriteLine("Stop: thread " + Thread.CurrentThread.ManagedThreadId);
//timer.Dispose();
_thread.Abort();
}
#region IDisposable Members
public void Dispose()
{
Console.WriteLine("Dispose: thread " + Thread.CurrentThread.ManagedThreadId);
//timer.Dispose();
_thread.Abort();
}
#endregion
}
You have two issues, both separate:
In Watcher.Changed's handler you call Thread.Sleep(3000);
This is poor behaviour in a callback of a thread you do not own (since it is being supplied by the pool owned/used by the watcher. This is not the source of your problem though. This it in direct violation of the guidelines for use
You use statics all over the place which is horrible, and has likely led you into this problem:
static void test()
{
_eventsRaised += 1;
//if it was more than a second since the last event (ie, it's a new save), then wait for 3 seconds (to avoid
//multiple events for the same file save) before processing
if (DateTime.Now.Ticks - _lastEventTicks > 1000)
{
Thread.Sleep(3000);
_lastEventTicks = DateTime.Now.Ticks;
_eventsRespondedTo += 1;
Console.WriteLine("File changed. Handled event {0} of {1}.", _eventsRespondedTo, _eventsRaised);
//stop threads and then restart them
thread1.Stop();
thread2.Stop();
thread1 = new WorkerThread("foo", 20);
thread2 = new WorkerThread("bar", 30);
}
}
This callback can fire repeatedly on multiple different threads (it uses the system thread pool for this) You code assumes that only one thread will ever execute this method at a time since threads can be created but not not stopped.
Imagine: thread A and B
A thread1.Stop()
A thread2.Stop()
B thread1.Stop()
B thread2.Stop()
A thread1 = new WorkerThread()
A thread2 = new WorkerThread()
B thread1 = new WorkerThread()
B thread2 = new WorkerThread()
You now have 4 WorkerThread instances on the heap but only two variables referencing them, the two created by A have leaked. The event handling and callback registration with the timer means that theses leaked WorkerThreads are kept alive (in the GC sense) despite you having no reference to them in your code. they stay leaked for ever.
There are other flaws in the design but this is a critical one.
No, no, no, no, no, no, no. Never use Thread.Abort().
Read the MSDN docs on it.
The thread is not guaranteed to abort immediately, or at all. This situation can occur if a thread does an unbounded amount of computation in the finally blocks that are called as part of the abort procedure, thereby indefinitely delaying the abort. To wait until a thread has aborted, you can call the Join method on the thread after calling the Abort method, but there is no guarantee the wait will end.
The correct way to end a thread is to signal to it that it should end, then call Join() on that thread. I usually do something like this (pseudo-code):
public class ThreadUsingClass
{
private object mSyncObject = new object();
private bool mKilledThread = false;
private Thread mThread = null;
void Start()
{
// start mThread
}
void Stop()
{
lock(mSyncObject)
{
mKilledThread = true;
}
mThread.Join();
}
void ThreadProc()
{
while(true)
{
bool isKilled = false;
lock(mSyncObject)
{
isKilled = mKilledThread;
}
if (isKilled)
return;
}
}
}
Well, having had some time to look into this again, it appears that the memory leak is a bit of a red herring. When I stop writing to the console, the memory usage stops increasing.
However, there is a remaining issue in that every time I edit the test.xml file (which fires the Changed event on the FileSystemWatcher, whose handler sets flags that cause the worker classes to be renewed and therefore threads/timers to be stopped), the memory increases by about 4K, providing that I am using explicit Threads, rather Timers. When I use a Timer, there is no problem. But, given that I would rather use a Timer than a Thread, this is no longer an issue to me, but I would still be interested in why it is occuring.
See the new code below. I've created two classes - WorkerThread and WorkerTimer, one of which uses Threads and the other Timers (I've tried two Timers, the System.Threading.Timer and the System.Timers.Timer. with the Console output switched on, you can see the difference that this makes with regards to which thread the tick event is raised on). Just comment/uncomment the appropriate lines of MainThread.Start in order to use the required class. For the reason above, it is recommended that the Console.WriteLine lines are commented out, except when you want to check that everything is working as expected.
class Program
{
static void Main(string[] args)
{
MainThread.Start();
}
}
public class MainThread
{
private static int _eventsRaised = 0;
private static int _eventsRespondedTo = 0;
private static bool _reload = false;
private static readonly object _reloadLock = new object();
//to do something once in handler, though
//this code would go in onStart in a windows service.
public static void Start()
{
WorkerThread thread1 = null;
WorkerThread thread2 = null;
//WorkerTimer thread1 = null;
//WorkerTimer thread2 = null;
//Console.WriteLine("Start: thread " + Thread.CurrentThread.ManagedThreadId);
//watch config
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = "../../";
watcher.Filter = "test.xml";
watcher.EnableRaisingEvents = true;
//subscribe to changed event. note that this event can be raised a number of times for each save of the file.
watcher.Changed += (sender, args) => FileChanged(sender, args);
thread1 = new WorkerThread("foo", 10);
thread2 = new WorkerThread("bar", 15);
//thread1 = new WorkerTimer("foo", 10);
//thread2 = new WorkerTimer("bar", 15);
while (true)
{
if (_reload)
{
//create our two threads.
//Console.WriteLine("Start - reload: thread " + Thread.CurrentThread.ManagedThreadId);
//wait, to enable other file changed events to pass
//Console.WriteLine("Start - waiting: thread " + Thread.CurrentThread.ManagedThreadId);
thread1.Dispose();
thread2.Dispose();
Thread.Sleep(3000); //each thread lasts 0.5 seconds, so 3 seconds should be plenty to wait for the
//LoadData function to complete.
Monitor.Enter(_reloadLock);
//GC.Collect();
thread1 = new WorkerThread("foo", 5);
thread2 = new WorkerThread("bar", 7);
//thread1 = new WorkerTimer("foo", 5);
//thread2 = new WorkerTimer("bar", 7);
_reload = false;
Monitor.Exit(_reloadLock);
}
}
}
//this event handler is called in a separate thread to Start()
static void FileChanged(object source, FileSystemEventArgs e)
{
Monitor.Enter(_reloadLock);
_eventsRaised += 1;
//if it was more than a second since the last event (ie, it's a new save), then wait for 3 seconds (to avoid
//multiple events for the same file save) before processing
if (!_reload)
{
//Console.WriteLine("FileChanged: thread " + Thread.CurrentThread.ManagedThreadId);
_eventsRespondedTo += 1;
//Console.WriteLine("FileChanged. Handled event {0} of {1}.", _eventsRespondedTo, _eventsRaised);
//tell main thread to restart threads
_reload = true;
}
Monitor.Exit(_reloadLock);
}
}
public class WorkerTimer : IDisposable
{
private System.Threading.Timer _timer; //the timer exists in its own separate thread pool thread.
//private System.Timers.Timer _timer;
private string _name = string.Empty;
/// <summary>
/// Initializes a new instance of the <see cref="WorkerThread"/> class.
/// </summary>
/// <param name="name">The name.</param>
/// <param name="interval">The interval, in seconds.</param>
public WorkerTimer(string name, int interval)
{
_name = name;
//Console.WriteLine("WorkerThread constructor: Called from thread " + Thread.CurrentThread.ManagedThreadId);
//_timer = new System.Timers.Timer(interval * 1000);
//_timer.Elapsed += (sender, args) => LoadData();
//_timer.Start();
_timer = new Timer(Tick, null, 1000, interval * 1000);
}
//this delegate instance does NOT run in the same thread as the thread that created the timer. It runs in its own
//thread, taken from the ThreadPool. Hence, no need to create a new thread for the LoadData method.
private void Tick(object state)
{
LoadData();
}
//Loads the data. Called from separate thread. Lasts 0.5 seconds.
//
private void LoadData()
{
for (int i = 0; i < 10; i++)
{
//Console.WriteLine(string.Format("Worker thread {0} ({2}): {1}", _name, i, Thread.CurrentThread.ManagedThreadId));
Thread.Sleep(50);
}
}
public void Stop()
{
//Console.WriteLine("Stop: called from thread " + Thread.CurrentThread.ManagedThreadId);
//_timer.Stop();
_timer.Change(Timeout.Infinite, Timeout.Infinite);
//_timer = null;
//_timer.Dispose();
}
#region IDisposable Members
public void Dispose()
{
//Console.WriteLine("Dispose: called from thread " + Thread.CurrentThread.ManagedThreadId);
//_timer.Stop();
_timer.Change(Timeout.Infinite, Timeout.Infinite);
//_timer = null;
//_timer.Dispose();
}
#endregion
}
public class WorkerThread : IDisposable
{
private string _name = string.Empty;
private int _interval = 0; //thread wait interval in ms.
private Thread _thread = null;
private ThreadStart _job = null;
private object _syncObject = new object();
private bool _killThread = false;
public WorkerThread(string name, int interval)
{
_name = name;
_interval = interval * 1000;
_job = new ThreadStart(LoadData);
_thread = new Thread(_job);
//Console.WriteLine("WorkerThread constructor: thread " + _thread.ManagedThreadId + " created. Called from thread " + Thread.CurrentThread.ManagedThreadId);
_thread.Start();
}
//Loads the data. Called from separate thread. Lasts 0.5 seconds.
//
//private void LoadData(object state)
private void LoadData()
{
while (true)
{
//check to see if thread it to be stopped.
bool isKilled = false;
lock (_syncObject)
{
isKilled = _killThread;
}
if (isKilled)
return;
for (int i = 0; i < 10; i++)
{
//Console.WriteLine(string.Format("Worker thread {0} ({2}): {1}", _name, i, Thread.CurrentThread.ManagedThreadId));
Thread.Sleep(50);
}
Thread.Sleep(_interval);
}
}
public void Stop()
{
//Console.WriteLine("Stop: thread " + _thread.ManagedThreadId + " called from thread " + Thread.CurrentThread.ManagedThreadId);
//_thread.Abort();
lock (_syncObject)
{
_killThread = true;
}
_thread.Join();
}
#region IDisposable Members
public void Dispose()
{
//Console.WriteLine("Dispose: thread " + _thread.ManagedThreadId + " called from thread " + Thread.CurrentThread.ManagedThreadId);
//_thread.Abort();
lock (_syncObject)
{
_killThread = true;
}
_thread.Join();
}
#endregion
}
Well you never actually call dispose on the WorkerThread instances.
The actual worker threads aren't being disposed when the watched file event occurs. I think I would rewrite this so that new threads aren't created, but they are reinitialized. Instead of calling Stop and recreating the threads, call a new Restart method that just stops and resets the timer.
You never terminate the threads - use something like Process Explorer to check whether the thread count is increasing as well as memory. Add a call to Abort() in your Stop() method.
Edit: You did, thanks.

Categories

Resources