Pause/Resume thread whith AutoResetEvent - c#

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);
}
}
}

Related

Pausing a method until a button click

How can i pause a method execution or the current iteration until the user press next button for example?
I want an efficient way because i can't divide the method into other methods and I don't want to use Thread.Sleep() because it freezes the GUI.
public void Calc(int x)
{
while(x < 4)
{
//My Work
textbox1.Text += "Press next to continue";
//Need to pause the iteration until taking a signal from a button
}
}
void button1(...)
{
Calc(1);
}
Use SemaphoreSlim
You can run both work and button code on UI thread, thanks to async/await scheduling. And you can reuse same semaphore instance to make multiple signals.
//not signaled semaphore with maximum of 1 signal
SemaphoreSlim _workSignal = new SemaphoreSlim(0,1);
Your work code:
async void DoWork()
{
//Do Something
//this tries to decrease signal count and if signal count is 0,
//waits until it will have some signals, then "takes"
//one signal to go through.
//After this line the semaphore will be in non-signaled state
await _workSignal.WaitAsync();
//Do more
}
Your button handler
void Button_Click(...)
{
_signal.Release();//increases signal count, allowing your work code to go through
}
I think a simple ManualResetEvent along with async method may help you:
public partial class Form1 : Form
{
private ManualResetEvent _calcEvent;
private delegate void ChangeTextMethod(string text);
private ChangeTextMethod _changeTextHandler;
public Form1()
{
InitializeComponent();
_calcEvent = new ManualResetEvent(false);
_changeTextHandler = delegate (string text) {
textbox1.Text += text;
};
}
private void button1_Click(object sender, EventArgs e)
{
Calc(1);
}
public async Task Calc(int x)
{
await Task.Run(() => {
while (x < 4)
{
//My Work
textbox1.Invoke(_changeTextHandler, "Press next to continue");
//Need to pause the iteration until taking a signal from a button
_calcEvent.WaitOne();
x = 4;
}
textbox1.Invoke(_changeTextHandler, "... continued");
});
}
private void button2_Click(object sender, EventArgs e)
{
_calcEvent.Set();
}
}

Only raise an event if the previous one was completed

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.)

UI freezes even process start with separate thread?

In My application have time consuming process.There fore i try to do that operation in separate thread.Even i Stared it separate thread my Main UI still freezes during the time of long running process.But still i couldn't figure out the reason for that?Some thing wrong in my code?
My Event Hander Code
private void BtnloadClick(object sender, EventArgs e)
{
if (null != cmbSource.SelectedItem)
{
string selectedITem = ((FeedSource) cmbSource.SelectedItem).Url;
if (!string.IsNullOrEmpty(selectedITem))
{
Thread starter = new Thread(() => BindDataUI(selectedITem));
starter.IsBackground = true;
starter.Start();
}
}
private void BindDataUI(string url)
{
if (feedGridView1.InvokeRequired)
{
BeginInvoke(new Action(() => BindDataGrid(url)));
}
else
BindDataGrid(ss);
}
private void BindDataGrid(string selectedItem)
{
for (int i = 0; i < 10; i++)
{
//Time consuming Process
}
}
Your thread is completely useless :-)
In your thread you are executing BindDataUI which marshals the execution back to the UI thread using Invoke.
Your complete code is equivalent to this:
private void BtnloadClick(object sender, EventArgs e)
{
if (null != cmbSource.SelectedItem)
{
string selectedITem = ((FeedSource) cmbSource.SelectedItem).Url;
if (!string.IsNullOrEmpty(selectedITem))
{
BindDataGrid(selectedITem);
}
}
private void BindDataGrid(string selectedItem)
{
for (int i = 0; i < 10; i++)
{
//Time consuming Process
}
}
It would be better to only marshal these parts of BindDataGrid to the UI thread that really need to run on this thread because they need to update the UI.

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();
}

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