I have c# app that has UI and background threads. Based on user input I like to stop and start the background thread. I have two options here as I see:
1) totally stop and then start background thread as new thread ( I have not been able to this. I keep getting my process ended message)
2) Pause the background thread until user click run again.
Here is the code that I call again after bw.CancelAsync();
private void StartBackgroundWorker()
{
bw = new BackgroundWorker();
bw.WorkerReportsProgress = true;
bw.WorkerSupportsCancellation = true;
bw.DoWork += bw_DoWork;
bw.RunWorkerCompleted += bw_RunWorkerCompleted;
bw.RunWorkerAsync("Background Worker");
}
you can't start and stop a background worker like that, but in your DoWork event, you can have it ask whether it should execute or wait.
you can also subclass BackgroundWorker (override the OnDoWork() method), and add start/pause methods to it that toggle a private wait handle, which is much nicer than having your UI know about the ManualResetEvent.
//using System.Threading;
//the worker will ask this if it can run
ManualResetEvent wh = new ManualResetEvent(false);
//this holds UI state for the start/stop button
bool canRun = false;
private void StartBackgroundWorker()
{
bw = new BackgroundWorker();
bw.WorkerReportsProgress = true;
bw.WorkerSupportsCancellation = true;
bw.DoWork += bw_DoWork;
bw.RunWorkerCompleted += bw_RunWorkerCompleted;
bw.RunWorkerAsync("Background Worker");
}
void bw_DoWork(object sender, DoWorkEventArgs e)
{
while(true)
{
//it waits here until someone calls Set() on wh (via user input)
// it will pass every time after that after Set is called until Reset() is called
wh.WaitOne()
//do your work
}
}
//background worker can't start until Set() is called on wh
void btnStartStop_Clicked(object sender, EventArgs e)
{
//toggle the wait handle based on state
if(canRun)
{
wh.Reset();
}
else {wh.Set();}
canRun= !canRun;
//btnStartStop.Text = canRun ? "Stop" : "Start";
}
You can always abort a thread and catch the ThreadAbortedException. Im not sure if this is the most neat solution since an exception causes a lot of overhead but i think it is better than spreading WaitOne in the code like Dan suggested.
Another solution is to inherit from the thread class, and add a function to this class that stops or pauses the thread. This way you can hide the details of the implementation.
Related
I'm trying to execute a thread without blocking UI , I've used this code but when I execute my application , it won't execute the thread and nothing is shown after clicking on DoButton event
public void DoThread()
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += MyFunctionDoThread;
var frame = new DispatcherFrame();
worker.RunWorkerCompleted += (sender, args) => {
frame.Continue = false;
};
worker.RunWorkerAsync();
Dispatcher.PushFrame(frame);
}
private void Dobutton_Click(object sender, RoutedEventArgs e)
{
DoThread(); // Process will be executed
}
public void MyFunctionDoThread()
{
// Some Tasks
ProcessStartInfo startInfo = new ProcessStartInfo();
Process.Start(startInfo);
// ...
}
How I can perform a task ( thread ) without blocking the UI?
You should really use Task/async/await for any background work. BackgroundWorker is rather old.
public async void Dobutton_Click(object sender, RoutedEventArgs e)
{
try{
var result = await Task.Run(MyFunctionDoThread);
// Update the UI, or otherwise deal with the result
}
catch{
// deal with failures, like showing a dialog to the user
}
}
how can I use it , the await require to return task action
await requires the method to be marked with async, it does not require the method to return a task. It is a guideline to return a task, so that the caller can deal with any failures. But for things like button event handlers you are at the end of the line, there is no one else to deal with any failure, so you should instead make sure you do it yourself with a try/catch.
I want to:
Show a form with a textbox.
Run an external program (notepad.exe for ease of example).
Continue to allow the user to enter data into the form textbox whilst notepad is running.
Run some more (continue) native form code when notepad closes. This will update the form, amongst other things.
I'm having problems making this happen. I'm aware of a multitude of posts about this similar issue, but haven't found a solution that works for me.
I have tried:
Doing a waitforexit, but this of course blocks the UI and users cannot enter data.
Attempting an asynchronous process call, where another method is called when this process is completed. This causes a problem where the new method is called from another thread and can't update the form.
Doing a wait/sleep loop in the UI, but again this will naturally block the UI.
What would be the neatest, and simplest solution for a simple Windows Form program? There are no extra classes used, and all code is in the Form1 class.
The Process class fires an Exited event when the process exits. You can add a handler to that event to execute code when the process exits without blocking the UI thread:
process.EnableRaisingEvents = true;
process.Exited += (s, args) => DoStuff();
Alternatively you could create a Task that represents the completion of the process to leverage the TPL for asynchrony:
public static Task WhenExited(this Process process)
{
var tcs = new TaskCompletionSource<bool>();
process.EnableRaisingEvents = true;
process.Exited += (s, args) => tcs.TrySetResult(true);
return tcs.Task;
}
This would allow you to write:
await process.WhenExited();
UpdateUI();
Here you go:
void Form1_Load(object sender, EventArgs e)
{
Task.Factory.StartNew(() =>
{
var p = Process.Start("notepad.exe");
p.WaitForExit();
}).ContinueWith(antecedant => { MessageBox.Show("Notepad closed"); });
}
Here is my favorite way to do something like this with a BackgroundWorker. This has the advantage of the RunWorkerCompleted callback being on the main thread, so it can interact with the UI.
public partial class Form1 : Form
{
...
private BackgroundWorker wrk;
private void button1_Click(object sender, EventArgs e)
{
wrk = new BackgroundWorker();
wrk.DoWork += (s, ea) => { /*Create your process and wait here*/ };
wrk.RunWorkerCompleted += (s, ea) => { textBox1.Text = "Finished"; };
wrk.RunWorkerAsync();
}
}
You should start process in BackgroundWorker so you can catch complete event on same thread.
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += delegate {
Process proc = Process.Start("YOUR-PROCESS-PATH");
proc.Start();
proc.WaitForExit();
}
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
worker.RunWorkerAsync();
then catch the worker ended event on called thread;
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//Do your thing o UI thread
}
I'm running some scripts in runtime, but it's freezing my UI, I'm calling the CodeProvider inside a Thread, but it still freezing.
In my form I call:
var mre = new ManualResetEvent(false);
Thread tr = new Thread(() =>
{
Script sp = new Script();
code = textBox.Text;
sp.Comp(code);
mre.Set();
});
tr.Start();
mre.WaitOne();
I'm using the mre.WaitOne() because I want to wait the thread finish to keep running my code.
Tried to use the same way inside the Compile method too:
public bool Comps(string code)
{
var mre = new ManualResetEvent(false);
Thread tr = new Thread(() =>
{
//Code to generate a CompilerResult and generate the assembly
Run();
mre.Set();
});
tr.Start();
mre.WaitOne();
return true;
}
But while it's waiting it still freezing the UI.
Any ideas?
Thanks
I'm using the mre.WaitOne() because I want to wait the thread finish
to keep running my code.
What did you expect to happen if you force the calling thread to freeze until your processing thread has completed processing? Doing it this way, there is no point in having that extra thread and if the calling thread is the UI thread, of course it will freeze.
If you do background processing you cannot wait for the result synchronously, instead you have to notify the UI in some sort of fashion that the processing is done, i.e. using a callback or dispatching the result back to the UI in some other form.
The entire point of multi-threading is to allow the Thread to execute on it's own, independent of any other threads. What you want to do is use a callback to signal the completion of your thread and then have your UI respond to the completion.
The BackgroundWorker class has an event already built in for this purpose.
There are three events you want to subscribe to:
bw.DoWork +=
new DoWorkEventHandler(bw_DoWork);
bw.ProgressChanged +=
new ProgressChangedEventHandler(bw_ProgressChanged);
bw.RunWorkerCompleted +=
new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
DoWork is where your work will happen. ProgressChanged allows you to update the UI of progress. RunWorkerCompleted will pop the event with your DoWork function has completed.
This object handles the threading and can be set to run asynchronously by running the bw.RunWorkerAsync() call.
See the following page for detail for this:
http://msdn.microsoft.com/en-us/library/cc221403%28v=vs.95%29.aspx
As an example:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
MessageBox.Show(String.Format("UI thread: {0}", Thread.CurrentThread.ManagedThreadId));
this.Invoke(new MethodInvoker(delegate() { MessageBox.Show(String.Format("Invoke thread: {0}", Thread.CurrentThread.ManagedThreadId)); }));
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
MessageBox.Show(String.Format("Worker thread: {0}", Thread.CurrentThread.ManagedThreadId));
}
}
This example can be built by adding one button and one background worker to a form. Wire up the events through the events designer for the button1_Click and the backgroundWorker1_DoWork function. You should have three MessagesBoxes that pop up after clicking button1. You'll notice the Id for the UI thread and the Invoke thread are the same, which means that any processing you do from the invoke will cause your UI thread to wait. The third popup is from the worker thread, which has a different ID.
Use BeginInvoke when done. For example:
delegate void MyAction();
void Form1_Load( object sender, EventArgs e )
{
Thread tr = new Thread( () =>
{
Script sp = new Script();
code = textBox.Text;
sp.Comp(code);
BeginInvoke( new MyAction( ThreadOperationEnded ) );
} );
tr.Start();
}
void ThreadOperationEnded()
{
MessageBox.Show( "Finished!" );
}
I'm working on asynchronous operation which needs to invoke further asynchronous tasks. I'm trying to keep it simple by using BackgroundWorkers, with the result being that one BackgroundWorker's DoWork() callback calls a method which creates a second BackgroundWorker, like so (minus error checking and all that jazz for brevity):
class Class1
{
private BackgroundWorker _worker = null;
public void DoSomethingAsync()
{
_worker = new BackgroundWorker();
_worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(_worker_RunWorkerCompleted);
_worker.DoWork += new DoWorkEventHandler(_worker_DoWork);
_worker.RunWorkerAsync();
}
void _worker_DoWork(object sender, DoWorkEventArgs e)
{
Class2 foo = new Class2();
foo.DoSomethingElseAsync();
while(foo.IsBusy) Thread.Sleep(0); // try to wait for foo to finish.
}
void _worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// do stuff
}
}
class Class2
{
private BackgroundWorker _worker = null;
Thread _originalThread = null;
public AsyncCompletedEventHandler DoSomethingCompleted;
public bool IsBusy { get { return _worker != null && _worker.IsBusy; } }
public void DoSomethingElseAsync()
{
_originalThread = Thread.CurrentThread;
_worker = new BackgroundWorker();
_worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(_worker_RunWorkerCompleted);
_worker.DoWork += new DoWorkEventHandler(_worker_DoWork);
_worker.RunWorkerAsync();
}
void _worker_DoWork(object sender, DoWorkEventArgs e)
{
// do stuff
}
void _worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Debug.Assert(Thread.CurrentThread == _originalThread); // fails
// Assuming the above Assert() were excluded, the following event would be raised on the wrong thread.
if (DoSomethingCompleted != null) DoSomethingCompleted(this, new AsyncCompletedEventArgs(e.Error, e.Cancelled, null));
}
}
So the problem is, I'm expecting Class2._Worker_RunWorkerCompleted() to execute on the same thread on which Class2.DoSomethingElseAsync() was called. This never happens - instead, the callback runs on a completely new thread.
Here's my suspicion: Class1's _worker_DoWork() never returns, which means that thread would never get back to an event listener, even if one existed (I suspect one doesn't). On the other hand, if _worker_DoWork() did return, Class1's BackgroundWorker would automatically finish prematurely - it needs to wait for Class2 to finish working before it can finish its work.
That leads to two questions:
Is my suspicion correct?
What's the best way to nest asynchronous operations like this? Can I salvage the BackgroundWorker approach, or is there some other, more suitable technique?
If a BackgroundWorker is created on the UI thread, DoWork will run on a thread pool thread and RunWorkerCompleted will run on the UI thread.
If a BackgroundWorker is created on a background thread (ie not the UI thread) DoWork will still run on a thread pool thread and RunWorkerCompleted will also run on a thread pool thread.
In your case, since you can't marshal a call to an arbitrary (thread pool) thread, you won't be able to guarantee the behaviour you want, although you might want to take a look at System.Threading.SynchronizationContext.
You should use ManualResetEvent to communicate between threads:
http://msdn.microsoft.com/en-us/library/system.threading.manualresetevent%28VS.71%29.aspx
Firstly, I can't see anywhere that actually starts running the worker. You could change the DoSomethingAsync method (also add the call to the DoSomethingElseAsync method in Class2)
public void DoSomethingAsync()
{
_worker = new BackgroundWorker();
_worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(_worker_RunWorkerCompleted);
_worker.DoWork += new DoWorkEventHandler(_worker_DoWork);
_worker.RunWorkerAsync(); // add this line to start it
}
Secondly, the work handler (the _worker_DoWork method) is not guaranteed to be on the same thread as the call to DoSomethingAsync - this is the whole point of the Background Worker. ie/ to do work on another thread. The same applies for worker complete handler (the _worker_RunWorkerCompleted method).
Finally, It doesn't seem to make sense to attach the two different background workers unless the top level one (Class1) always requires Class2 work to happen too. You would be better of having a single manager to handle each background worker.
I'm currently writing a little GUI program that does some work and exits afterwards. While work is done, the GUI thread is updated with infos for the user.
This is the pattern I'm currently using and I'm thinking it's not the most elegant one:
static void MainForm_Loaded(BeoExport exporter)
{
// Thread 1 runs the Export
workerThread = new Thread(() =>
{
exporter.StartExport();
// don't exit immediately, so the user sees someting if the work is done fast
Thread.Sleep(1000);
});
// Thread 2 waits for Thread 1 and exits the program afterwards
waiterThread = new Thread(() =>
{
workerThread.Join();
Application.Exit();
});
workerThread.Start();
waiterThread.Start();
}
So what pattern/mechanics would you use to do the same?
To clarify: I was not interested in a way to update the GUI thread. That's already done. This might sound esoteric but I was lookig for the right way to quit the application.
If I could, I would give Dave the credits, since he pointed out the usefulness of the BackgroundWorker.
Have you considered a BackgroundWorker thread instead? You can use its ReportProgress method and ProgressChanged event to update the GUI (with a progress bar perhaps), assuming that you can refactor BeoExport.StartExport method to also report progress. This gives the users visible feedback that work is actually happening.
I don't understand why do you use two threads. You can use threadpool:
ThreadPool.QueueUserWorkItem((state)=>{
exporter.StartExport();
Thread.Sleep(1000);
Application.Exit();
});
I suggest you to use the BackgroundWorker class. It's thought to do the kind of job you're doing. You could do domething like this:
public class Form1 : Form
{
private BackgroundWorker worker;
private ProgressBar bar;
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
bar= new ProgressBar();
bar.Dock = DockStyle.Top;
Controls.Add(bar);
worker = new BackgroundWorker();
worker.WorkerReportsProgress=true;
worker.RunWorkerCompleted += delegate
{
Close();
};
worker.ProgressChanged += delegate(object sender, ProgressChangedEventArgs ev)
{
bar.Value = ev.ProgressPercentage;
};
worker.DoWork += worker_DoWork;
worker.RunWorkerAsync();
}
void worker_DoWork(object sender, DoWorkEventArgs e)
{
//do your work here. For the example, just sleep a bit
//and report progress
for (var i = 0; i < 100;i++ )
{
Thread.Sleep(50);
worker.ReportProgress(i);
}
}
}
You can use an AutoResetEvent. The main thread waits for the autoreset event to be reset.
var wh = new AutoResetEvent(false);
var workerThread = new Thread(() =>
{
exporter.StartExport();
// don't exit immediately, so the user sees something if the work is done fast
Thread.Sleep(5000);
wh.Set();
});
workerThread.Start();
wh.WaitOne();
Application.Current.Shutdown();
Have you taken a look at the Task Parallel Library in .net 4 you can set up a task and the library will work out to best pararellise it for you, either threading, working a seperate CPU core's the is a load of great information about it online.
Regards
Iain
To add a little to Lain's answer, here's a Console sample using a Task from the System.Threading.Tasks namespace.
class Program
{
static void Main(string[] args)
{
Task<int> task = Task<int>.Factory.StartNew(() =>
{
Exporter exporter = new Exporter();
int i = exporter.StartExport();
return i;
});
int iResult = task.Result;
Console.WriteLine(iResult);
Console.ReadLine();
}
class Exporter {
public int StartExport()
{
//simulate some work
System.Threading.Thread.Sleep(500);
return 5;
}
}
}
Using a BackgroundWorker might help you implement your background processing. If you wanted to stick with your current pattern then consider the following.
static void MainForm_Loaded(BeoExport exporter)
{
workerThread = new Thread(() =>
{
exporter.StartExport();
Thread.Sleep(1000);
MainForm.BeginInvoke(
(Action)(() =>
{
MainForm.Close();
});
});
workerThread.IsBackground = true;
workerThread.Start();
}
Have the worker thread send a notification message of some description to the main thread. The GUI can then either exit or display a "done" message as appropriate.