I have the following code to look for new files in the directory:
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = #"C:\temp\Dir1\";
watcher.Created += new FileSystemEventHandler(OnChanged);
watcher.EnableRaisingEvents = true;
and the OnChanged event handler:
public void OnChanged(object source, FileSystemEventArgs e)
{
Thread t = new Thread(readFile);
t.Start(e.FullPath);
}
and the readFile thread method:
public void readFile(){
FSReader vsfr = new FSReader((string)path);
while (vsfr.EndOfStream == false)
{
PrintLine(vsfr.ReadLine());
}
vsfr.Close();
}
So every time a new file is created, it's being read by readFile thread. The problem occurs when the first file is being read and the second file starts to be read by another thread.
What I need is first thread to get terminated when the second thread opens so there's only a single thread running at a time to read a single file. I know that I need to use lock and events to accomplish this.
When I use lock on the readFile method, I get the desired result of a single thread running at once, but I still need a way to tell the previous thread to close, when new thread opens. How can I do this?
Any tips? Thanks.
Sounds pretty easy, just add a lock when you reading files and some simple cancelation
string _path;
Thread
object _lock = new object();
volatile bool _running;
volatile bool _cancel;
public void OnChanged(object source, FileSystemEventArgs e)
{
// waiting
while(_running)
{
_cancel = true;
Thread.Sleep(0);
}
// start new thread
_cancel = false;
_path = e.FullPath;
(new Thread(ReadFile)).Start();
}
public void ReadFile()
{
lock(_lock)
{
_running = true;
using(var reader = new FSReader(_path))
while (!reader.EndOfStream)
{
if(_cancel)
break;
PrintLine(reader.ReadLine());
}
_running = false;
}
}
I assume, you want to have only 1 thread working at a time.
When creating a new thread, you have to check if it is already running and if is, then set cancel and wait for it to finish.
It is possible to keep Thread instance and check IsAlive instead of using _running.
You could use Task instead of Thread. You can use ManualResetEvent to avoid need for a sleep, though in this scenario Sleeps looks harmless to me.
Edit
Let's play with it
volatile bool _cancel;
Mutex _mutext = new Mutex(false);
public void OnChanged(object source, FileSystemEventArgs e)
{
_cancel = true;
_mutex.WaitOne();
// start new thread
_cancel = false;
_mutex.ReleaseMutex();
(new Thread(ReadFile)).Start(e.FullPath);
}
public void ReadFile(string path)
{
_mutex.WaitOne();
using(var reader = new FSReader(path))
while (!reader.EndOfStream)
{
if(_cancel)
break;
PrintLine(reader.ReadLine());
}
_mutex.ReleaseMutex();
}
Now we are using Mutex to ensure, what no new thread will be started, until existing (if any) will finish its work. No need for lock (mutex do all the job).
Edit
Actually, there is a slim but chance, what if OnChanged will be called before thread takes mutex ownership (it's possible in theory), then we are in trouble.
Solution would be to implementing sort of ping-pong waiting between thread and event (two mutexes, or perhaps some other synchronization primitive).
I'd do something along these lines. Obviously add your own locks/synchronisation.
while (vsfr.EndOfStream == false)
{
if (cancelThread)
{
vsfr.Close()
return;
}
PrintLine(vsfr.ReadLine());
}
and
public void OnChanged(object source, FileSystemEventArgs e)
{
Thread t = new Thread(readFile);
//If a thread is running, set the cancellation flag = true
//If you have some class-level reference to the running thread, you can then wait for it to .Join()
//Set cancellation flag back to false
t.Start(e.FullPath);
}
Related
islem = new Thread(new ThreadStart(ilk));
islem2 = new Thread(new ThreadStart(ikinci));
islem3 = new Thread(new ThreadStart(ucuncu));
islem4 = new Thread(new ThreadStart(dorduncu));
islem.Start();
islem2.Start();
islem3.Start();
islem4.Start();
if (!islem.IsAlive)
{
islem2.Suspend();
islem3.Suspend();
islem4.Suspend();
}
I want to do when islem is done. Other threads suspend but it doesn't work
I read about ManualResetEvent but I can't figure out multi-threading examples.They works just one thread simples. Also I read http://www.albahari.com/threading/part4.aspx#_Suspending_and_Resuming this paper to and look similar questions like C# controlling threads (resume/suspend) How to pause/suspend a thread then continue it? Pause/Resume thread whith AutoResetEvent I am working multi - thread objects
If you just need to cancel the worker threads, the very simplest approach is to use a flag. You have to mark the flag volatile to ensure all threads are using the same copy.
private volatile bool _done = false;
void Main()
{
StartWorkerThreads();
}
void WorkerThread()
{
while (true)
{
if (_done) return; //Someone else solved the problem, so exit.
ContinueSolvingTheProblem();
}
_done = true; //Tell everyone else to stop working.
}
If you truly want to pause (I'm not sure why) you can use a ManualResetEvent. This allows blocking behavior without consuming resources for the paused thread.
//When signalled, indicates threads can proceed.
//When reset, threads should pause as soon as possible.
//Constructor argument = true so it is set by default
private ManualResetEvent _go = new ManualResetEvent(true);
void Main()
{
StartWorkerThreads();
}
void WorkerThread()
{
while (true)
{
_go.WaitOne(); //Pause if the go event has been reset
ContinueSolvingTheProblem();
}
_go.Reset(); //Reset the go event in order to pause the other threads
}
You can also combine the approaches, e.g. if you wanted to be able to pause the threads, do some more work, then cancel them:
private volatile bool _done = false;
private ManualResetEvent _go = new ManualResetEvent(true);
void Main()
{
StartWorkerThreads();
}
void WorkerThread()
{
while (true)
{
if (_done) return; //Exit if problem has been solved
_go.WaitOne(); //Pause if the go event has been reset
if (_done) return; //Exit if problem was solved while we were waiting
ContinueSolvingTheProblem();
}
_go.Reset(); //Reset the go event in order to pause the other threads
if (VerifyAnswer())
{
_done = true; //Set the done flag to indicate all threads should exit
}
else
{
_go.Set(); //Tell other threads to continue
}
}
Consider the following code:
using (var mre = new ManualResetEvent(false))
{
var bgWkr = new BackgroundWorker();
bgWkr.DoWork += delegate(object sender, DoWorkEventArgs e)
{
var mrEvent = e.Argument as ManualResetEvent;
// some processing...
mrEvent.WaitOne();
// broadcast an event
};
bgWkr.RunWorkerAsync(mre);
// some other processing...
// hook into the same event
mre.Set();
}
Let's say that the spawned worker takes a bit of time to complete. We will have left the using block a while ago by the time the worker thread finishes and waits on the ManualResetEvent. I would assume that the mre would have been closed when leaving the using block (given that it would have been disposed) and this would throw an exception at the very least. Is this a safe assumption to make?
This example may not be the best one with the ManualResetEvent but it is to illustrate the case where we access an IDisposable object inside an anonymous method within a using block and the anonymous method is called after we have exited the using block. Is there some mechanism that keeps hold of the disposable object? I don't believe so but would like some confirmation as to why (if there is some sort of voodoo at work) or why not.
Cheers,
Yes, this code is wrong - the outcome is not really defined, but it would be quite reasonable for it to throw an exception at the mrEvent.WaitOne(), since mrEvent is the almost-certainly-now-disposed ManualResetEvent. Technically there's a chance that the worker thread was all ready to go, and the worker thread did its "some processing..." faster than the primary thread did the "some other processing...", but: I wouldn't rely on it. So in most cases: mrEvent is dead already.
As for how to avoid this: perhaps this simply isn't a scenario for using. But it occurs that since the worker thread does a WaitOne, the worker thread's WaitOne cannot complete before the primary thread performs the mre.Set() call - so you could exploit that and move the using to the worker:
var mre = new ManualResetEvent(false);
var bgWkr = new BackgroundWorker();
bgWkr.DoWork += delegate(object sender, DoWorkEventArgs e)
{
using(var mrEvent = e.Argument as ManualResetEvent)
{
// some processing...
mrEvent.WaitOne();
}
// broadcast an event
};
bgWkr.RunWorkerAsync(mre);
// some other processing...
// hook into the same event
mre.Set();
Note, however, that this raises an interesting question of what happens if the primary thread throws an exception in the "some other processing..." - the call to mre.Set() would never be reached, and the worker thread would never exit. You might want to do the mre.Set() in a finally:
var mre = new ManualResetEvent(false);
try {
var bgWkr = new BackgroundWorker();
bgWkr.DoWork += delegate(object sender, DoWorkEventArgs e)
{
using(var mrEvent = e.Argument as ManualResetEvent)
{
// some processing...
mrEvent.WaitOne();
}
// broadcast an event
};
bgWkr.RunWorkerAsync(mre);
// some other processing...
}
finally {
// hook into the same event
mre.Set();
}
In response to my comment (rather than proposing the answer to the question), I created a class to close the ManualResetEvent once done with it without the need to track when the last thread has finished using it. Thanks to Marc Gravell for the idea to close it once the WaitOne has completed. I am exposing it here should anybody else need it.
P.S. I'm constrained to .NET 3.5... hence why I am not using the ManualResetEventSlim.
Cheers,
Sean
public class OneTimeManualResetEvent
{
private ManualResetEvent _mre;
private volatile bool _closed;
private readonly object _locksmith = new object();
public OneTimeManualResetEvent()
{
_mre = new ManualResetEvent(false);
_closed = false;
}
public void WaitThenClose()
{
if (!_closed)
{
_mre.WaitOne();
if (!_closed)
{
lock (_locksmith)
{
Close();
}
}
}
}
public void Set()
{
if (!_closed)
_mre.Set();
}
private void Close()
{
if (!_closed)
{
_mre.Close();
_closed = true;
}
}
}
Okay, so my issue is that I have to catch delete and rename events (which) I can do. And modify the data in threads to handle this so that the deleted files are removed and the renamed files have their data changed. This is psuedo-code for the system, just to get an idea of what it looks like. Whenever I delete, the system throws an exception, however it is not caught, so I have been having a hard time figuring out how to go about solving or rewriting the solution. The other portion of this is that I will have multiple managers running at once, but I figure if I can't get one to work... then this is futile.
Main
{
public void Run()
{
List<FileInfo> someData = new List<FileInfo>();
FileWatcher fileWatcher = new FileWatcher(#"C:\USers\user1\Documents");
fileWatcher.NotifyFilter = NotifyFilter.Last
fileWatcher.Deleted += new FileSystemEventHandler(OnDelete);
fileWatcher.EnableRaisingEvents = true;
Manager aManager = new Manager(someData);
Thread aThread = new Thread(new ThreadStart(aManager.ExecuteTask));
aThread.Start();
}
static void OnDelete(object sender, Event e)
{
aManager.Pause();
aManager.RemoveData(e.FileInfo);
aManager.Resume();
}
}
Manager
{
ExecuteTask()
{
while(someData.Count > 0)
{
while (paused) ; // <- This is something I am trying to add
PreformSubTask(someData[0]);
}
}
PreformSubTask()
{
lock (_locker)
{
Worker someWorker = new Worker(someData[0]);
Thread someThread = new Thread(new ThreadStart(worker.ExecuteTask()));
}
worker.Join(someSetOfTime);
lock(_locker)
{
someData.RemoveAt(0);
}
}
Pause()
{
lock (_locker)
{
if (!paused) paused = true;
}
}
Resume
{
lock (_locker)
{
if (paused) paused = false;
}
}
RemoveData(FileInfo toRemove)
{
someData.RemoveAll(sd => sd.Equals(someData));
}
}
You should use thread synchronization to protect data shared between multiple threads from being corrupted. See the lock keyword or the Mutex class.
But, I'd really recommend not re-writing task queueing/scheduling and use something off-the-shelf.
What is wrong with simply doing the processing in the OnDelete handler?
I've a little program, that parses all the log files created by another program, and locked by it ( so, no way I can edit or delete those files) . The program runs just fine, and I do it starting a new Task every 10 seconds:
System.Timers.Timer aTimer = new System.Timers.Timer();
public Form1()
{
InitializeComponent();
aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
aTimer.Interval = 10000;
aTimer.Start();
}
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
var t = Task<int>.Factory.StartNew(() => convert());
}
the only problem arises when there are too many log files : if a new Task is started before the end of the previous one, the program crashes.
So, any idea on how to solve this behaviour, or better solutions to the problem?
You could use the lock() statement to lock on an object variable. On the other hand, you might run into thread deadlocks if the parsing of the log files consistently takes longer than the timer interval.
In your OnTimedEvent() function, I would check a boolean member variable that skips the parsing if you are already performing a parse. For example:
public class MyTimerClass
{
private bool isParsing;
// Other methods here which initiate the log file parsing.
private void OnTimedEvent(object sender, ElapsedEventArgs e)
{
if (!isParsing)
{
isParsing = true;
ParseLogFiles();
isParsing = false;
}
}
}
The simple solution would be to wait until the previous task is completed.
Write an event that sends a callback when the file is done being parsed.
This is the best I can do with the code provided.
Have you tried to use lock statement inside OnTimeEvent?
http://msdn.microsoft.com/en-us/library/c5kehkcz(v=VS.100).aspx
You could create a static boolean variable called IsRunning and set it to true when you are moving the logs, before you start moving the logs just check if IsRunning is set to true.
private static bool IsRunning = false;
public void MoveLogs()
{
if (!IsRunning)
{
IsRunning = true;
//Copy log files
IsRunning = false;
}
}
In the current accepted answer there is still the possibility of a race condition in a multi-threaded situation. However unlikely in your case because of the interval, another more threading appropriate solution is to use Monitor.TryEnter
public class MyTimerClass
{
private object _syncObject = new object();
// Other methods here which initiate the log file parsing.
private void OnTimedEvent(object sender, ElapsedEventArgs e)
{
if (Monitor.TryEnter(_syncObject) )
{
try
{
ParseLogFiles();
}
finally
{
Monitor.Exit(_syncObject);
}
}
}
}
I believe this is cleaner and gets you in the habit of using the proper thread synchronization mechanism in the framework.
Problem statement
I have a worker thread that basically scans a folder, going into the files within it, and then sleeps for a while. The scanning operation might take 2-3 seconds but not much more. I'm looking for a way to stop this thread elegantly.
Clarification: I want to stop the thread while it's sleeping, and not while it's scanning. However, the problem is that I do not know what is the current state of the thread. If it's sleeping I want it to exit immediately. If it's scanning, I want it to exit the moment it tries to block.
Attempts at a solution
At first I was using Sleep and Interrupt. Then I found out that Interrupt doesn't really interrupt the Sleep - it only works when the threads TRIES to go into sleeping.
So I switched to Monitor Wait&Pulse. Then I found out that the Pulse only works when I'm actually in the Wait. So now I have a thread which looks like that:
while (m_shouldRun)
{
try
{
DoSomethingThatTakesSeveralSeconds();
lock (this)
{
Monitor.Wait(this, 5000);
}
}
catch (ThreadInterruptedException)
{
m_shouldRun = false;
}
}
And now I need to craft my Stop function. So I started with:
public void Stop()
{
m_shouldRun = false;
lock (this)
{
Monitor.Pulse(this);
}
thread.Join();
}
But this doesn't work because I may be pulsing while the thread works (while it's not waiting). So I added Interrupt:
public void Stop()
{
m_shouldRun = false;
thread.Interrupt();
lock (this)
{
Monitor.Pulse(this);
}
thread.Join();
}
Another option is to use:
public void Stop()
{
m_shouldRun = false;
while (!thread.Join(1000))
{
lock (this)
{
Monitor.Pulse(this);
}
}
}
The question
What is the preferred method? Is there a third method which is preferable?
Another alternative is to use events:
private ManualResetEvent _event = new ManualResetEvent(false);
public void Run()
{
while (true)
{
DoSomethingThatTakesSeveralSeconds();
if (_event.WaitOne(timeout))
break;
}
}
public void Stop()
{
_event.Set();
thread.Join();
}
The way to stop a thread elegantly is to leave it finish by itself. So inside the worker method you could have a boolean variable which will check whether we want to interrupt. By default it will be set to false and when you set it to true from the main thread it will simply stop the scanning operation by breaking from the processing loop.
I recommend to keep it simple:
while (m_shouldRun)
{
DoSomethingThatTakesSeveralSeconds();
for (int i = 0; i < 5; i++) // example: 5 seconds sleep
{
if (!m_shouldRun)
break;
Thread.Sleep(1000);
}
}
public void Stop()
{
m_shouldRun = false;
// maybe thread.Join();
}
This has the following advantages:
It smells like busy waiting, but it's not. $NUMBER_OF_SECONDS checks are done during the waiting phase, which is not comparable to the thousands of checks done in real busy waiting.
It's simple, which greatly reduces the risk of error in multi-threaded code. All your Stop method needs to do is to set m_shouldRun to false and (maybe) call Thread.Join (if it is necessary for the thread to finish before Stop is left). No synchronization primitives are needed (except for marking m_shouldRun as volatile).
I came up with separately scheduling the task:
using System;
using System.Threading;
namespace ProjectEuler
{
class Program
{
//const double cycleIntervalMilliseconds = 10 * 60 * 1000;
const double cycleIntervalMilliseconds = 5 * 1000;
static readonly System.Timers.Timer scanTimer =
new System.Timers.Timer(cycleIntervalMilliseconds);
static bool scanningEnabled = true;
static readonly ManualResetEvent scanFinished =
new ManualResetEvent(true);
static void Main(string[] args)
{
scanTimer.Elapsed +=
new System.Timers.ElapsedEventHandler(scanTimer_Elapsed);
scanTimer.Enabled = true;
Console.ReadLine();
scanningEnabled = false;
scanFinished.WaitOne();
}
static void scanTimer_Elapsed(object sender,
System.Timers.ElapsedEventArgs e)
{
scanFinished.Reset();
scanTimer.Enabled = false;
if (scanningEnabled)
{
try
{
Console.WriteLine("Processing");
Thread.Sleep(5000);
Console.WriteLine("Finished");
}
finally
{
scanTimer.Enabled = scanningEnabled;
scanFinished.Set();
}
}
}
}
}