I'm having the worst time wrapping my head around threads/background processes. My issues seem common enough to a certain point but I've yet to find a good example that meets my needs.
The classic example goes like this:
My UI freezes when a certain long running task/process runs -I want to be able to at least move/minimize the UI.
Classic replies include Threading and Task Factories and BackgroundWorker solutions.
but no matter how I implement them I get poor results.
In my program, I'm executing another application and waiting for it to finish. For the sake of simplicity let's say I'm doing it like so:
Process p = Process.Start("notepad.exe somefile.txt");
p.WaitForExit();
//read somefile.txt
Clearly my application UI would hang while WaitForExit() grinds away waiting for me to close notepad.
I've attempted a number of suggested means around this but I get painted into one of two corners:
My interface still hangs, then reads somefile.txt just fine when I close notepad.
The Process (Notepad) runs fine but my application reads somefile.txt immediately before I have closed notepad (So I guess it's running asynchronously)
Most examples I see involve counting to a high number -simple but not quite what I'm doing. Firing off this "external" process complicates things a bit.
Thanks for your time and consideration!!
BackgroundWorker seems appropriate here; it should be configured something along those lines:
var worker = new BackgroundWorker();
worker.WorkerReportsProgress = false;
worker.WorkerSupportsCancellation = false;
worker.DoWork += worker_DoWork;
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
worker.RunWorkerAsync();
Then you have the handlers:
void worker_DoWork(object sender, DoWorkEventArgs e)
{
//start notepad process here.
}
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//read somefile.txt here.
}
From the sounds of things your application isn't running the Process.WaitForExit call on a separate thread otherwise there wouldn't be any hanging.
BackgroundWorker, Thread and the ThreadPool are all useful tools, but they can be difficult and cumbersome to work with and get right, the Task Parallel Library with System.Threading.Task has somewhat "superseded" using threads directly for most operations you need to perform asynchronously.
See: Threads and the new Task library in C#
So your code becomes.
Task.Factory.StartNew(() =>
{
var proc = new Process("...");
proc.WaitForExit();
File.Read("...");
});
Related
I have a main thread that invokes multiple backgroundworkers (in .net/c#).
Each of these threads starts a process in order to run an executable.
When a process ends, I want to tell the main thread to kill all other threads and their respective processes. After all of them stopped, I want to know this and continue to run the main thread for post-processing.
I keep a list of these external processes so I have no problem killing them all. My problem is how to kill all these backgroundworkers. I tried to keep a list of the threads associated with them and kill them from within the first thread that terminates, but apparently this does not kill the backgroundworker itself because the runworkercompleted method is still invoked multiple times.
Does anyone have a pattern on how to kill those workers in a nice way ? should I somehow notify the main thread to do the killing of the other workers ?
I'd recommend using async/await and CancellationTokenSources. I'll give advice on how to use BackgroundWorkers as well, but since async/await is so much more convenient (and shorter), it goes first.
async/await is convenient because it gives you the features you're looking for without much added complexity.
private async void SomeEvent(object sender, EventArgs e)
{
CancellationTokenSource cts = new CancellationTokenSource();
var waiter1 = DoSomething(cts.Token);
var waiter2 = DoSomethingElse(cts.Token);
// etc.
// Wait for the first one to finish, then cancel
await Task.WhenAny(waiter1, waiter2, ...).ConfigureAwait(false);
cts.Cancel();
// wait for the remainder to finish
await Task.WhenAll(waiter1, waiter2, ...).ConfigureAwait(false);
// Do Postprocessing
}
Your "waiters" look something like this:
private async Task DoSomething(CancellationToken token)
{
// Do stuff
// Periodically check if someone has finished
if (Token.IsCancellationRequested)
{
// clean up
return;
}
}
async/await code has a few gotchas, including deadlock. Since this sounds like a quick project (I could be wrong), it seems like a good place to learn - especially if there's no massive codebase to rework. If you want to learn more, I think Stephen Cleary's blog is a good place to start, particularly his intro.
On the other hand, if you're absolutely sure you want to use BackgroundWorkers... well I don't blame you, but I don't envy you either.
First, your workers have to know whether somebody else finished first. Use the finished BackgroundWorker's RunWorkerCompleted method to cancel the others BackgroundWorkers:
private void RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
// Check for errors...
}
else if (e.Cancelled)
{
// Mark that this one has finished
}
else
{
// Assuming you have a set of BackgroundWorkers called "workers"
foreach (var bgw in workers)
bgw.CancelAsync();
// other stuff...
}
}
Then, add a bit of code at the end of your DoWork method to report the cancellation...
private void DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
// Do stuff...
// When "RunWorkerCompleted" is called, let it know whether this worker has been cancelled.
e.Cancel = worker.CancellationPending;
}
And that's it. You can also check the worker.CancellationPending periodically to see if you can finish earlier, but don't forget to assign worker.CancellationPending to e.Cancel before your return!
One last thing: if you want the postprocessing to continue when all workers have finished (and only then), you need to have a way to mark when a particular worker is finished (to cancel the others), and then a way to find out when they've all finished (so you can begin postprocessing). It's doable, and not too difficult - off the top of my head, I'd use a Dictionary<BackgroundWorker, bool> to indicate which workers have finished. Still, that's another piece of clutter you can avoid with async/await.
From this answer it seems there is no way to kill a Backgroundworker. However this answer shows a workaround by overriding OnDoWork and keeping a reference to Thread.CurrentThread. I would still try to have those Backgroundworkers check for a notification to cancel, though.
I want to wait for x hours before executing some code in C#. i thought using a timer would be a good idea. (using thread.sleep does not seem right). But it just does not work. i am using the following code:
static void Main(string[] args)
{
System.Timers.Timer timer = new System.Timers.Timer();
timer.Interval = x * 3600000;
timer.Enabled = true;
timer.Elapsed += (o, e) => SomeFunction(username);
timer.AutoReset = true;
timer.Start();
}
this code supposed to wait for x hours and then execute SomeFunction but when i debug it, the main function ends after timer.start().
do you see any problem here? or can you suggest an alternative besides thread.sleep or await Task.Delay() ?
As soon as your Main function exits, your process ends, along with any background threads including timers.
You need to keep your main thread alive using Thread.Sleep(), Console.ReadKey() or whatever seems appropriate.
Alternatively, if you don't want to keep your process alive, you can register a scheduled task with Windows to be run in an hour's time, and then end.
There are two problems here. The first is that an executable will exit when all foreground threads are finished running. The only foreground thread is that going through Main() so it will then exit.
The second is that you aren't storing timer anywhere. Even if another thread was keeping the executable going, timer is eligible for garbage collection perhaps as soon as timer.Start() returns and certainly after Main() exits.
using thread.sleep does not seem right
It generally isn't a good idea, but considering that you only have one thread anyway, and considering that you have to have at least one foreground thread in an application, Thread.Sleep seems perfectly reasonable in this particular case. Task.Delay just as much.
More generally, I think I would prefer this to be either a scheduled task or a service. In particular, in cases where I want to wait hours before something is done, I very often want this to survive reboots.
Check out Quartz.Net and this for scheduled tasks.
so when i try and press "button 2" I expect two things to happen a)"dowsomething" is suppose to do its thing in the "now" class. b) Whilst its doing something i want it to count how long that something takes. However because "dosomething" is program hungry Form1 freezes and it wont run the timer. Im a bit of a rookie at c# so I wouldn't know how to run it in the background. So any outside the box ideas? Thanks.
int time = 0;
private void button2_Click(object sender, EventArgs e)
{
timer1.Start();
nowthen now = new nowthen();
now.dosomething(withthis); //This task is program hungry and causes the form to freeze
timer1.Stop();
time = 0;
}
private void timer1_Tick(object sender, EventArgs e)
{
time = time + 1;
label2.Text = time.ToString();
label2.Refresh();
}
In Windows Forms, all of your UI stuff runs on one thread. That includes the timer - the timer is implemented behind the scenes with windows messages.
Your question is actually two questions:-
How can I time an operation in C# / Windows forms?
How to time something depends on the precision you're looking for. For accuracy in the region of +/- 10ms then you can use Environment.TickCount - store it's value before your operation, then get the value again after, and subtract the stored value - and you have your duration.
More precise is the Stopwatch class in System.Threading - see http://www.dotnetperls.com/stopwatch
How can I run a task "in the background" ?
To run your operation in the background, you need to run it in a different thread. The easiest, designed friendly (but perhaps not all that flexible way) is to use the BackgroundWorker component. This wraps using a worker thread to do an operation for you. See http://www.dotnetperls.com/backgroundworker for a good explanation of how to do that.
More advanced, and more flexible, is to create your own thread to do the work. However, that will create some important issues to consider around how to syncronize what's going on - as soon as you start your thread, your method call finishes (it's asyncronous) and you need to have a mechanism for notifiying your UI code that the process has finished. This example seems as good as any on how to create your own thread: http://www.daveoncsharp.com/2009/09/create-a-worker-thread-for-your-windows-form-in-csharp/
For .NET 4 use:
Task.Factory.StartNew((Action) delegate()
{
// this code is now executing on a new thread.
nowthen now = new nowthen();
now.dosomething(withthis);
// to update the UI from here, you must use Invoke to make the call on UI thread
textBox1.Invoke((Action) delegate()
{
textBox1.Text = "This update occurs on the UI thread";
});
});
If you just want to time how long something takes, use System.Diagnostics.Stopwatch.
Stopwatch sw = Stopwatch.StartNew();
nowThen = new nowThen();
no.dosomething(withthis);
sw.Stop();
// you can get the time it took from sw.Elapsed
That won't, however, update a label with the elapsed time.
I guess I'll throw this in too, although it's not as elegant looking as #paul's solution.
timer1.Start();
var bw = new BackgroundWorker();
bw.DoWork += (s, e) => { now.dosomething((myArgumentType)e.Argument); };
bw.RunWorkerCompleted += (s, e) => { timer1.Stop(); };
bw.RunWorkerAsync(withthis);
This starts your timer, creates a new BackgroundWorker thread, tells it what to run in the DoWork method (dosomething runs in a separate thread), then stops the timer in the RunWorkerCompleted method (after dosomething is finished, control returns to the main thread in RunWorkerCompleted).
I have been writing ASP.NET web application for years now, but haven't really worked on large windows forms projects. I now need to work on one, so I am looking on some pointers on how a large windows forms project should ideally be structured. More specifically, I would like to know how to handle multiple threads. Assume you have a process which takes some time to complete - you do not want to have the ui window frozen and not responding. So that logic needs to move in a separate thread. If this thread accesses the UI, then it will cause exceptions. Invoke seems to do the trick, but looks very ugly and cumbersome to write and read!
So, in reality, what are the best practices? What type of threads should one launch, and how should these threads be split between UI and logic? Any sample code to get started?
here is a short way to use the backgroundworker
public Form1()
{
InitializeComponent();
BackgroundWorker worker = new BackgroundWorker();
worker.WorkerReportsProgress = true; //set to true to fire the progress-changed event
worker.DoWork += doWork;
worker.ProgressChanged += progressChanged;
}
void progressChanged(object sender, ProgressChangedEventArgs e)
{
int progress = e.ProgressPercentage; //Progress-Value
object userState = e.UserState; //can be used to pass values to the progress-changed-event
}
void doWork(object sender, DoWorkEventArgs e)
{
object argument = e.Argument; //Parameters for the call
bool cancel = e.Cancel; //Boolean-Value for cancel work
object result = e.Result; //Object for a return-value
}
As soon as you use a different thread you will have to switch back to the UI thread when touching the UI.
someForm.BeginInvoke() can do this but there are more options.
The BackgroundWorker can do the switching for you.
In .NET 4.5/ C# 5 you can use async/await; the continuation will be called on the original thread.
In general, try to untangle the logic as much as you can from the UI so you do not need to switch thread too often.
There are lots of ways to achieve UI responsiveness, execute long running tasks, achieve parallelism. You have to select the right way for your application -
This article by Jon Skeet is always a bonus to start with.
You can call Synchronous methods Asynchronously using any of these styles as per your application design and requirements
More difficult situations, such as coordinating the work of multiple threads, or handling threads that block
There are a number of ways to expose asynchronous features to client code. Read here for the Event-based Asynchronous Pattern - which prescribes the recommended way for classes to present asynchronous behavior.
Background Worker comes in handy when you have a single long running task.
Hope this gives you a head start.
I have some code that I wrote, which does what I want. However, I am not quite sure how, exactly, it works. The part I am having the most trouble with is the last part. I had a textBox1.Text = "test" which did not work. I got a run time error about it being called from a different thread. When I put the textBox1.Invoke(etc etc), it worked as expected. Why?
As you can see, I know just enough to be dangerous and I really want to understand what's going on here instead of blindly copying and pasting from sites around the web.
I have the following in a class named SerialCommunicator:
public SerialCommunicator(SerialPort sp)
{
this.sp = sp;
sp.ReceivedBytesThreshold = packetSize;
sp.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived);
sp.Open();
}
public void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
Thread.Sleep(50);
SerialPort s = (SerialPort)sender;
byte[] buffer = new byte[128];
s.Read(buffer, 0, s.BytesToRead);
}
Then, in my Form1.cs I have a button that when pressed does the following:
private void btnPortOK_Click(object sender, EventArgs e)
{
string comPort = cboComPorts.SelectedItem.ToString();
SerialPort sp = new SerialPort(comPort, 9600, Parity.None, 8, StopBits.One);
sp.DataReceived += new SerialDataReceivedEventHandler(DataHasBeenReceived);
comm = new SerialCommunicator(sp);
}
public void DataHasBeenReceived(object sender, EventArgs args)
{
textBox1.Invoke(new EventHandler(delegate { textBox1.Text += "test"; }));
}
This is thread-affinity. UI controls don't like to be touched by anything except the thread that created them, but the DataReceived thread happens from a different thread. Adding a call toControl.Invoke pushes an item of work back to the UI thread, so the Text updated can succeed.
I am not an expert on this (there will likely be better answers than this). But as I understand it, the GUI thread "owns" your form. So when you try to update it from a different thread you are crossing the streams.
The Invoke is a way to ask the GUI thread to run a method. Method that it runs is your textBox1.Text += "test";
The idea is by invoking a delegate, that will ask the GUI thread to make the change, rather than just changing the value yourself. This allows allow the change to be done in a thread safe manner.
Here is a good article by Jon Skeet on this issue:
http://www.yoda.arachsys.com/csharp/threads/winforms.shtml
Events are called from the thread where they happen. (Unless specified otherwise).
Think about this way:
When you activate the event, it is actually called as a finction EventName(). So calling an event means actually going to all the methods that were registered to that event and doing them.
But, this is done in the same thread in a serial way.
So if an event happened in a thread that is not your UI thread you'll get theat error.
The issue is that the GUI components only accepts modifications from the GUI thread. So when other threads want to modify the GUI, then they must queue their modification code using measures like control.Invoke(...) which will queue the delegate to be processed as soon as possible on the GUI event queue, and thus the correct thread.
What you run in to is that one of the built-in checks are fired than controls that the calling thread indeed is the correct thread. It is a security measure that makes debugging easier (if they were not present you would have to debug subtle threading issues instead...)
textBox1.Text = "test" doesn't work because you are calling it from another thread (i.e. the DataHasBeenReceived event) then the thread who owns the textbox. That's usually the thread in which your application runs and that creates your GUI interface (and thus your textbox). Invoke works because that methods switches to the GUI thread, sets your text and then switches back to the thread of your DataHasBeenReceived event.
In Net 1.0 and 1.1 you could use GUI controls from another thread then then the one that owned them but this resulted in a lot of problems when threads started accessing the controls at the same time. So, since net 2.0 Microsoft changed that.
If you want to know if must use invoke or not (i.e. if a method can be called from the both the GUI thread or another thread), you can use the property InvokeRequired combined with an if else. A invoke call is slightly more expensive then a direct manipulation of the control.