Modifying data being used in a thread - c#

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?

Related

Main process gets frozen after starting another thread

I am trying to write an application which transfers data between 2 systems. This application is used by a user, so it is WinForm application. When data transfering is started by a click of the user, the GUI gets frozen even though I start the data transfering in another thread. I am doing something wrong but I couldnt figure it out. here is my SIMPLIFIED code below....
What am I doing wrong?
// Button Click Event
private void btnStart_Click(object sender, EventArgs e)
{
StartThread();
}
// This starts the threaad.
public static void StartThread()
{
string msg = string.Empty;
int i = 0;
continue_ = true;
if (list != null)
{
while (continue_)
{
i++;
Thread.Sleep(5000);
Thread thrd1 = new System.Threading.Thread(() => Test());
thrd1.Start();
}
}
}
// This is a simplified code.
public static void Test()
{
string msg = string.Empty;
int i = 0;
continue_ = true;
while (continue_)
{
i++;
Thread.Sleep(5000);
FormMain.dal.ExecuteQuery("INSERT INTO A_TEST VALUES('"+i+"')",null,CommandType.Text,out msg);
}
}
Your StartThread() method includes a Thread.Sleep(5000) ... this is happening in your button click method, thus is making the UI thread sleep. Also, it looks like you have an infinite loop on the UI thread as continue_ never gets set to false
I'm guessing what you're trying to achieve here, but this may help:
public static void StartThread()
{
Thread thrd1 = new System.Threading.Thread(() => Test());
thrd1.Start();
}
Let's have a look at this block in StartThread:
while (continue_)
{
i++;
Thread.Sleep(5000);
Thread thrd1 = new System.Threading.Thread(() => Test());
thrd1.Start();
}
You have a while loop dependen on continue_, but you never change it to false. So you get first of all an infinite loop, which causes the GUI to freeze.
why you are modifying i, but never using it, so just remove it.
You don't need also Thread.Sleep(5000);. However, if you really want to wait a time period, you can use an async delay. It will give the GUI free, so that the GUI works until the delay is finished. But for this, you have to declare StartThread as async.
In your:
if (list != null)
{
while (continue_)
{
i++;
Thread.Sleep(5000);
Thread thrd1 = new System.Threading.Thread(() => Test());
thrd1.Start();
}
}
You use Thread.Sleep(5000);
This however still targets your main thread.
I would suggest you to remove this line.
Also, why do you use the variable 'i' while you never use it?

Code Help for ThreadPool

Have created a class which implements ThreadPool. The code is as below:
public sealed class PyeThreadPool :
IDisposable
{
private readonly object _lock = new object();
private readonly int _minThreadCount;
private readonly int _maxThreadCount;
private readonly Queue<Action> _queue = new Queue<Action>();
private int _totalThreadCount;
private int _waitingThreadCount;
private bool _disposed;
public PyeThreadPool(int minThreadCount, int maxThreadCount)
{
if (minThreadCount < 0)
throw new ArgumentOutOfRangeException("minThreadCount");
if (maxThreadCount < 1 || maxThreadCount < minThreadCount)
throw new ArgumentOutOfRangeException("maxThreadCount");
_minThreadCount = minThreadCount;
_maxThreadCount = maxThreadCount;
}
public void Dispose()
{
lock (_lock)
{
_disposed = true;
// if there are thread waiting, they should stop waiting.
if (_waitingThreadCount > 0)
Monitor.PulseAll(_lock);
}
}
/// <summary>
/// Executes an action in a parallel thread.
/// </summary>
public void RunParallel(Action action)
{
if (action == null)
throw new ArgumentNullException("action");
lock (_lock)
{
if (_disposed)
throw new ObjectDisposedException(GetType().FullName);
bool queued = false;
if (_waitingThreadCount == 0)
{
if (_totalThreadCount < _maxThreadCount)
{
_totalThreadCount++;
var thread = new Thread(_ThreadRun);
thread.Name = "Worker Thread";
thread.Start(action);
queued = true;
}
}
if (!queued)
{
_queue.Enqueue(action);
Monitor.Pulse(_lock);
}
}
}
private void _ThreadRun(object firstAction)
{
Action action = (Action)firstAction;
firstAction = null;
// we always start a new thread with an action, so we get it immediately.
// but, as we don't know what that action really holds in memory, we set
// the initial action to null, so after it finishes and a new action is get,
// we will let the GC collect it.
while (true)
{
action();
lock (_lock)
{
if (_queue.Count == 0)
{
// we started waiting, so new threads don't need to be created.
_waitingThreadCount++;
while (_queue.Count == 0)
{
if (_disposed)
return;
if (_totalThreadCount > _minThreadCount)
{
_totalThreadCount--;
_waitingThreadCount--;
return;
}
action = null;
Monitor.Wait(_lock);
}
// we finished waiting.
_waitingThreadCount--;
}
action = _queue.Dequeue();
// we just get a new action, and we will release the lock and return
// to the while, where the action will be executed.
}
}
}
}
I have tried to use this and the test code is as:
PyeThreadPool MyPool;
int x = 1;
protected void Page_Load(object sender, EventArgs e)
{
MyPool = new PyeThreadPool(4, 6);
}
void showMessage(string message)
{
TxtMessage.Text = message;
}
protected void BtnStartThread_Click(object sender, EventArgs e)
{
x++;
int arg = x;
MyPool.RunParallel(() =>
{
showMessage(arg.ToString());
});
}
Problem is:
(1) When I execute this either in debug or release mode I do not see the result in textbox, on the other hand I see the result when I step through. What am I missing here, why I can not see the output.
(2) The RunParallel method shows only one thread even if I have set maxcount to more than 1. Is there any code logic missing or is it because the test application is simple?
Thanks !
You should have a look at SmartThreadPool library. It is one of the best alternative to ThreadPool.
Its features (copied from source link)
Smart Thread Pool is a thread pool written in C#. The implementation was first based on Stephan Toub's thread pool with some extra features, but now, it is far beyond the original. Here is a list of the thread pool features:
The number of threads dynamically changes according to the workload on the threads in the pool.
Work items can return a value.
A work item can be cancelled if it hasn't been executed yet.
The caller thread's context is used when the work item is executed (limited).
Usage of minimum number of Win32 event handles, so the handle count of the application won't explode.
The caller can wait for multiple or all the work items to complete.
A work item can have a PostExecute callback, which is called as soon the work item is completed.
The state object that accompanies the work item can be disposed automatically.
Work item exceptions are sent back to the caller.
Work items have priority.
Work items group.
The caller can suspend the start of a thread pool and work items group.
Threads have priority.
Threads have initialization and termination events.
WinCE platform is supported (limited).
Action and Func generic methods are supported.
Silverlight is supported.
Mono is supported.
Performance counters (Windows and internal).
Work item timeout (passive).
Threads ApartmentState
Threads IsBakcground
Threads name template
Windows Phone is supported (limited)
Threads MaxStackSize
The problem is you are attempting to update a UI control from a background thread. Not allowed.
You need to do a BeginInvoke or Invoke in your ShowMessage function.

Reading one file at a time

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

How to terminate a worker thread correctly in c#

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

Background worker synchronization

Lets say I have a class that is supposed to generate some ID (for example GUID) for me. Now unfortunately the ID generation is a somewhat long process and if I need a hundred of those I run into a problem of significant slowdowns. In order to avoid those, I keep a queue of pre-generated ID, and when this queue starts to run down on them I use the BackgroundWorker to generate new ones and place them in the queue. But there are some problems I've run into. The biggest one at the moment is how to make sure that in case the queue compleatelly runs out on IDs the main thread waits for the BackroundWorker to generate and place them in the queue. Heres the code that I have at the moment.
public class IdGenerator
{
private Queue<string> mIds = new Queue<string>();
private BackgroundWorker mWorker = new BackgroundWorker();
private static EventWaitHandle mWaitHandle = new AutoResetEvent(false);
public IdGenerator()
{
GenerateIds();
this.mWorker.DoWork += new DoWorkEventHandler(FillQueueWithIds);
}
private void GenerateIds()
{
List<string> ids = new List<string>();
for (int i = 0; i < 100; i++ )
{
ids.Add(Guid.NewGuid().ToString());
}
lock (this.mIds)
{
foreach (string id in ids)
{
this.mIds.Enqueue(id);
}
}
}
public string GetId()
{
string id = string.Empty;
lock (this.mIds)
{
if (this.mIds.Count > 0)
{
id = this.mIds.Dequeue();
}
if (this.mIds.Count < 100)
{
if (!this.mWorker.IsBusy)
{
this.mWorker.RunWorkerAsync();
}
}
}
if (this.mIds.Count < 1)
{
mWaitHandle.WaitOne();
}
return id;
}
void FillQueueWithIds(object sender, DoWorkEventArgs e)
{
GenerateIds();
mWaitHandle.Set();
}
}
Obviously it doesn't work correctly. It seems that I have a problem with proper timing for calling WaitOne and Set methods. And sometimes the IsBusy property returns true even though the worker has already completed his work.
EDIT:
Its a WinForm and I'm required to use .NET 2.0
The problem you have is the classic Producer-Consumer problem. Take a look at http://en.wikipedia.org/wiki/Producer-consumer_problem
A simple explanation is that you will have two threads. One will be the producer (the GUID generator) and the other will be the consumer.
You will keep these threads in synch through the use of semaphores. The semaphore will be the responsible to stop the producer when the queue is full and to stop the consumer when it is empty.
The process is all very well explained at the Wikipedia article and I bet you can find a basic implementation of Producer-Consumer in c# on the internet.
In .NET 4 you can use the BlockingCollection<T> and more generically IProducerConsumerCollection<T>
Here's an example of 2 tasks, one adding and the other taking, using it.
http://msdn.microsoft.com/en-us/library/dd997306.aspx
There are some bugs related to thread sync, see in changed code below.
When you apply lock sync to queue pay attention to put under lock all uses of queue.
I've changed GetId method to probe for new ids if there are none.
public class IdGenerator
{
private Queue<string> mIds = new Queue<string>();
private BackgroundWorker mWorker = new BackgroundWorker();
private static EventWaitHandle mWaitHandle = new AutoResetEvent(false);
public IdGenerator()
{
GenerateIds();
this.mWorker.DoWork += new DoWorkEventHandler(FillQueueWithIds);
}
private void GenerateIds()
{
List<string> ids = new List<string>();
for (int i = 0; i < 100; i++ )
{
ids.Add(Guid.NewGuid().ToString());
}
lock (this.mIds)
{
foreach (string id in ids)
{
this.mIds.Enqueue(id);
}
}
}
public string GetId()
{
string id = string.Empty;
//Indicates if we need to wait
bool needWait = false;
do
{
lock (this.mIds)
{
if (this.mIds.Count > 0)
{
id = this.mIds.Dequeue();
return id;
}
if (this.mIds.Count < 100 && this.mIds.Count > 0)
{
if (!this.mWorker.IsBusy)
{
this.mWorker.RunWorkerAsync();
}
}
else
{
needWait = true;
}
}
if (needWait)
{
mWaitHandle.WaitOne();
needWait = false;
}
} while(true);
return id;
}
void FillQueueWithIds(object sender, DoWorkEventArgs e)
{
GenerateIds();
mWaitHandle.Set();
}
}
Your main code (presumably WinForms) calls mWaitHandle.WaitOne() at a certain point. At that moment the Messagepump is blocked and the Bgw will be unable to call its Completed event. That means the IsBusy flag remain true: deadlock.
Similar issues can arise if code inside DoWork throws an exception.
Edit:
I would think that you could solve most problems by using a ThreadPool thread to replace the Bgw. And a simple volatile bool isbusy flag.
OK, heres the final solution I went with. This one doesn't use the BackgroundWorker, but it works. Thanks to Edu who pointed to the Producer-Consumer problem. I used the example provided by MSDN located here.

Categories

Resources