Related
Suppose you have a search textbox and have a search algorithm attached to the TextChanged event, that runs with a BackgroundWorker. If there comes a new character in the textbox, i need to cancel the previous search and run it again.
I tried using events in between the main thread and the bgw, from this previous question, but I still get the error "currently busy and cannot run multiple tasks concurrently"
BackgroundWorker bgw_Search = new BackgroundWorker();
bgw_Search.DoWork += new DoWorkEventHandler(bgw_Search_DoWork);
private AutoResetEvent _resetEvent = new AutoResetEvent(false);
private void txtSearch_TextChanged(object sender, EventArgs e)
{
SearchWithBgw();
}
private void SearchWithBgw()
{
// cancel previous search
if (bgw_Search.IsBusy)
{
bgw_Search.CancelAsync();
// wait for the bgw to finish, so it can be reused.
_resetEvent.WaitOne(); // will block until _resetEvent.Set() call made
}
// start new search
bgw_Search.RunWorkerAsync(); // error "cannot run multiple tasks concurrently"
}
void bgw_Search_DoWork(object sender, DoWorkEventArgs e)
{
Search(txtSearch.Text, e);
}
private void Search(string aQuery, DoWorkEventArgs e)
{
int i = 1;
while (i < 3) // simulating search processing...
{
Thread.Sleep(1000);
i++;
if (bgw_Search.CancellationPending)
{
_resetEvent.Set(); // signal that worker is done
e.Cancel = true;
return;
}
}
}
EDIT To reflect answers. Don´t reuse the BackgroundWorker, create a new one:
private void SearchWithBgw()
{
if (bgw_Search.IsBusy)
{
bgw_Search.CancelAsync();
_resetEvent.WaitOne(); // will block until _resetEvent.Set() call made
bgw_Search = new BackgroundWorker();
bgw_Search.WorkerSupportsCancellation = true;
bgw_Search.DoWork += new DoWorkEventHandler(bgw_Search_DoWork);
}
bgw_Search.RunWorkerAsync();
}
When the _resetEvent.WaitOne() call completes, the worker thread isn't actually done. It is busy returning from DoWork() and waiting for an opportunity to run the RunWorkerCompleted event, if any. That takes time.
There is no reliable way to ensure the BGW is completed in a synchronous way. Blocking on IsBusy or waiting for the RunWorkerCompleted event to run is going to cause deadlock. If you really want to use only one bgw then you'll have to queue the requests. Or just don't sweat the small stuff and allocate another bgw. They cost very little.
Create a new background worker if the old one exists.
private void SearchWithBgw()
{
// cancel previous search
if (bgw_Search.IsBusy)
{
bgw_Search.CancelAsync();
// wait for the bgw to finish, so it can be reused.
_resetEvent.WaitOne(); // will block until _resetEvent.Set() call made
BackgroundWorker bgw_Search = new BackgroundWorker();
bgw_Search.DoWork += new DoWorkEventHandler(bgw_Search_DoWork);
}
// start new search
bgw_Search.RunWorkerAsync(); // error "cannot run multiple tasks concurrently"
}
Also I know you put fake code in, but you want to make sure you set _resetEvent when the code completes normally too.
Do not reuse a Backgroundworker. It is a cheap resource, it is not a Thread.
make sure your Bgw code stops, yours looks OK. The Bgw will release the Thread to the pool.
but in the mean time, create a new Task/Bgw for a new job.
You may want to unsubscribe your Completed event from the old Bgw.
I think you should consider not cancelling the background worker.
If you cancel requests and the user types faster than your server returns queries, he will not see suggestions until he is finished typing.
In interactive scenarios like this, It could be better to show responses that run behind with what the user's typing. Your user will know he can stop typing if the word he has in mind is your suggestions list.
This will be also better for your server when it is busy, because instead of many cancelled requests, who will cost something but that are ultimately not shown, there will be fewer requests whose response you actually use.
I ran into similar issues with (3d) rendering applications, where the beginner's mistake is to cancel and rerender on every mousemove. This lead to a lot of computation and little interactive feedback.
I am writing a GUI application.
The application is opening multiple threads during it's life time. One of the threads is handling events that can come from other applications, so it is waiting in a while(true) loop for the event which is never been terminated.
The user can close the application in any minute. I want to close all the threads that the main application had opened.
I am using Process.GetCurrentProcess().Kill(); to deal with this problem at the moment.
Is this a good solution? If not, why and what is the proper way to deal with this problem, how to close all threads that were opened by the main application?
If you create the new threads as background threads (by setting IsBackground before starting them), they will automatically stop when the main thread (the application thread) terminates.
(From MSDN):
A thread is either a background thread or a foreground thread. Background threads are identical to foreground threads, except that background threads do not prevent a process from terminating. Once all foreground threads belonging to a process have terminated, the common language runtime ends the process. Any remaining background threads are stopped and do not complete.
Once you already have threads waiting for some events, just add one more event that when triggered will instruct the thread to terminate.
In case you don't need to provide some means of graceful shutdown for other threads, you can switch them into the “background thread” mode to ensure automatic termination — see MSDN for a thorough discussion of this topic.
There are a lot of ways to deal with this, but ideally you want your threads to exit normally on their own rather than just killing the process.
You could do something very simple like this:
public class ThreadSignal
{
public bool Stop { get; set; }
}
Then in your thread loop, do:
public void DoWork(object state)
{
ThreadSignal signal = (ThreadSignal)state;
while(!signal.Stop)
{
// Do work here
}
}
Then when you're ready to stop, set your ThreadSignal.Stop to true. This is a very simple example, but it gives you a starting point.
You should wait in the loop with a ManualResetEvent (or AutoResetEvent).
Then just set a member variable to true when you are shutting down:
public class MyForm : Form
{
private AutoResetEvent _workTrigger = new AutoResetEvent();
private bool _shuttingDown = false;
private Thread _thread;
public void Form_Initialize()
{
_thread = new Thread(MyThreadMethod);
_thread.Start();
}
public static void MyThreadMethod(object State)
{
while (!_shuttingDown)
{
//wait for jobs.
_workTrigger.WaitOne(); //can add a timeout as parameter.
//do some work here
}
}
public void Form_Closing(object source, EventArgs e)
{
_shuttingDown = true;
_workTrigger.Set();
//wait for it to exit. You could use the timeout
//parameter and a loop to not block the UI
_thread.Join();
}
}
As you mentioned it's a GUI application so the main thread which is responsible for message loop is responsible for alerting the infinite (while(true)) loop that user wants to exit the program. I recommend to replace true with another boolean for signaling that user has closed the window like this: while(windowIsOpen) and set it to false on the unload of your form.
Don't lose your threads around the application - keep'em somewhere (List<Thread> will do fine). Then when the time is right (closing time) notify each one that it should finish what it's doing and exit.
Then, .Join() all of them, then allow application to exit.
Don't ever go to 'ThreadAbort' realm, it's dark side of the force that lurks there.
Generally how I do this is:
Create a Class that encapsulates this behavior (e.g. handling incoming messages in the background
Have the Class inherit from IDisposable. When Dispose() is called set a private variable named _disposed
Create my dedicated thread in my Class constructor.
Have a private AutoResetEvent named _workToDo. Your background thread will wait on this event and only do a work loop when this event is signaled.
Have a public method to send the message to your background worker that queues the work up and then sets _workToDo to tell your background thread to do the work.
Putting this all together, you get:
public class BackgroundProcessor : IDisposed
{
private Thread _backgroundThread;
private bool _disposed;
private AutoResetEvent _workToDo = new AutoResetEvent(false);
// where T is a class with the set of parameters for your background work
private Queue<T> _workQueue = Queue.Synchronized(new Queue<T>);
public BackgroundProcessor()
{
_backgroundThread = new Thread(DoBackgroundWork);
_backgroundThread.Start();
}
public void Dispose()
{
_disposed = true;
// Wait 5 seconds for the processing of any previously submitted work to finish.
// This gives you a clean exit. May want to check return value for timeout and log
// a warning if pending background work was not completed in time.
// If you're not sure what you want to do yet, a Debug.Assert is a great place to
// start because it will let you know if you do or don't go over time in general
// in your debug builds.
// Do *not* Join() and wait infinitely. This is a great way to introduce shutdown
// hangs into your app where your UI disappears but your process hangs around
// invisibly forever. Nasty problem to debug later...
Debug.Assert(_backgroundThread.Join(5000));
}
// Called by your 'other application'
public void GiveMeWorkToDo(T workParameters)
{
_workQueue.Enqueue(workParameters);
_workToDo.Set();
}
private void DoBackgroundWork()
{
while (!_disposed)
{
// 500 ms timeout to WaitOne allows your Dispose event to be detected if there is
// No work being submitted. This is a fancier version of a Thread.Sleep(500)
// loop. This is better because you will immediately start work when a new
// message is posted instead of waiting for the current Sleep statement to time
// out first.
_workToDo.WaitOne(500);
// It's possible multiple sets of work accumulated or that the previous loop picked up the work and there's none left. This is a thread safe way of handling this.
T workParamters = _workQueue.Count > 0 ? workParameters = _workQueue.Dequeue() : null;
do
{
DoSomething(workParameters);
workParameters = _workQueue.Count > 0 ? workParameters = _workQueue.Dequeue() : null;
} while (workParameters != null)
}
}
}
Consider using the BackGroundWorker class. Since it's using the threadpool (via BeginInvoke()), you'd get background threads. As a bonus you get convenient progress reporting, cancellation and completion callbacks (already marshalled to the UI thread).
I encountered a strange problem with our Windows C# / .NET application. Actually it is a GUI application, my job is the included network component, encapsulated in an assembly. I do not know the code of the main/GUI application, I could contact it's developer though.
Now the application's UI has buttons to "Start" and "Stop" the network engine. Both buttons work.
To make my component threadsafe I am using a lock around three methods. I dont't want a client to be able to call Stop() before Start() finished. Additinally there is a Polling Timer.
I tried to show you as few lines as possible and simpified the problem:
private Timer actionTimer = new Timer(new
TimerCallback(actionTimer_TimerCallback),
null, Timeout.Infinite, Timeout.Infinite);
public void Start()
{
lock (driverLock)
{
active = true;
// Trigger the first timer event in 500ms
actionTimer.Change(500, Timeout.Infinite);
}
}
private void actionTimer_TimerCallback(object state)
{
lock (driverLock)
{
if (!active) return;
log.Debug("Before event");
StatusEvent(this, new StatusEventArgs()); // it hangs here
log.Debug("After event");
// Now restart timer
actionTimer.Change(500, Timeout.Infinite);
}
}
public void Stop()
{
lock (driverLock)
{
active = false;
}
}
Here is how to reproduce my problem. As I said, the Start and Stop buttons both work, but if you press Start(), and during the execution of the TimerCallback press Stop(), this prevents the TimerCallback to return. It hangs exactly at the same position, the StatusEvent. So the lock is never released and the GUI also hangs, because it's call of the Stop() method cannot proceed.
Now I observed the following: If the application hangs because of this "deadlock" and I click on the application in the task bar with the right mouse button, it continues. It just works as expected then. Anybody has an explanation or better a solution for this?
By the way, I also tried it with InvokeIfRequired as I don't know the internas of the GUI application. This is neccesary if my StatusEvent would change something in the GUI.
Since I have no reference to the GUI controls, I used (assuming only one target):
Delegate firstTarget = StatusEvent.GetInocationList()[0];
ISynchronizeInvoke syncInvoke = firstTarget.Target as ISynchronizeInvoke;
if (syncInvoke.InvokeRequired)
{
syncInvoke.Invoke(firstTarget, new object[] { this, new StatusEventArgs() });
}
else
{
firstTarget.Method.Invoke(firstTarget.Target, new object[] { this, new StatusEventArgs() });
}
This approach didn't change the problem. I think this is because I am Invoking on the main application's event handlers, not on the GUI controls. So the main app is responsible for Invoking? But anyway, AFAIK not using Invoke although needed would not result in a deadlock like this but (hopefully) in an exception.
As for why right-click "unlocks" your application, my "educated guess" of events that lead to this behaviour is as follows:
(when your component was created) GUI registered a subscriber to the status notification event
Your component acquires lock (in a worker thread, not GUI thread), then fires status notification event
The GUI callback for status notification event is called and it starts updating GUI; the updates are causing events to be sent to the event loop
While the update is going on, "Start" button gets clicked
Win32 sends a click message to the GUI thread and tries to handle it synchronously
Handler for the "Start" button gets called, it then calls "Start" method on your component (on GUI thread)
Note that the status update has not finished yet; start button handler "cut in front of"
the remaining GUI updates in status update (this actually happens quite a bit in Win32)
"Start" method tries to acquire your component's lock (on GUI thread), blocks
GUI thread is now hung (waits for start handler to finish; start handler waits for lock; the lock is held by worker thread that marshalled a GUI update call to GUI thread and waits for the update call to finish; the GUI update call marshalled from worker thread is waiting for start handler that cut in front of it to finish; ...)
If you now right-click on taskbar, my guess is that taskbar manager (somehow) starts a "sub-event-loop" (much like modal dialogs start their own "sub-event-loops", see Raymond Chen's blog for details) and processes queued events for the application
The extra event loop triggered by the right-click can now process the GUI updates that were marshalled from the worker thread; this unblocks the worker thread; this in turn releases the lock; this in turn unblocks application's GUI thread so it can finish handling start button click (because it can now acquire the lock)
You could test this theory by causing your application to "bite", then breaking into debugger and looking at the stack trace of the worker thread for your component. It should be blocked in some transition to GUI thread. The GUI thread itself should be blocked in the lock statement, but down the stack you should be able to see some "cut in front of the line" calls...
I think the first recommendation to be able to track this issue down would be to turn on the flag Control.CheckForIllegalCrossThreadCalls = true;.
Next, I would recommend firing the notification event outside of the lock. What I usually do is gather information needed by an event inside a lock, then release the lock and use the information I gathered to fire the event. Something along the lines:
string status;
lock (driverLock) {
if (!active) { return; }
status = ...
actionTimer.Change(500, Timeout.Infinite);
}
StatusEvent(this, new StatusEventArgs(status));
But most importantly, I would review who are the intended clients of your component. From the method names and your description I suspect GUI is the only one (it tells you when to start and stop; you tell it when your status changes). In that case you should not be using a lock. Start & stop methods could simply be setting and resetting a manual-reset event to indicate whether your component is active (a semaphore, really).
[update]
In trying to reproduce your scenario I wrote the following simple program. You should be able to copy the code, compile and run it without problems (I built it as a console application that starts a form :-) )
using System;
using System.Threading;
using System.Windows.Forms;
using Timer=System.Threading.Timer;
namespace LockTest
{
public static class Program
{
// Used by component's notification event
private sealed class MyEventArgs : EventArgs
{
public string NotificationText { get; set; }
}
// Simple component implementation; fires notification event 500 msecs after previous notification event finished
private sealed class MyComponent
{
public MyComponent()
{
this._timer = new Timer(this.Notify, null, -1, -1); // not started yet
}
public void Start()
{
lock (this._lock)
{
if (!this._active)
{
this._active = true;
this._timer.Change(TimeSpan.FromMilliseconds(500d), TimeSpan.FromMilliseconds(-1d));
}
}
}
public void Stop()
{
lock (this._lock)
{
this._active = false;
}
}
public event EventHandler<MyEventArgs> Notification;
private void Notify(object ignore) // this will be invoked invoked in the context of a threadpool worker thread
{
lock (this._lock)
{
if (!this._active) { return; }
var notification = this.Notification; // make a local copy
if (notification != null)
{
notification(this, new MyEventArgs { NotificationText = "Now is " + DateTime.Now.ToString("o") });
}
this._timer.Change(TimeSpan.FromMilliseconds(500d), TimeSpan.FromMilliseconds(-1d)); // rinse and repeat
}
}
private bool _active;
private readonly object _lock = new object();
private readonly Timer _timer;
}
// Simple form to excercise our component
private sealed class MyForm : Form
{
public MyForm()
{
this.Text = "UI Lock Demo";
this.AutoSize = true;
this.AutoSizeMode = AutoSizeMode.GrowAndShrink;
var container = new FlowLayoutPanel { FlowDirection = FlowDirection.TopDown, Dock = DockStyle.Fill, AutoSize = true, AutoSizeMode = AutoSizeMode.GrowAndShrink };
this.Controls.Add(container);
this._status = new Label { Width = 300, Text = "Ready, press Start" };
container.Controls.Add(this._status);
this._component.Notification += this.UpdateStatus;
var button = new Button { Text = "Start" };
button.Click += (sender, args) => this._component.Start();
container.Controls.Add(button);
button = new Button { Text = "Stop" };
button.Click += (sender, args) => this._component.Stop();
container.Controls.Add(button);
}
private void UpdateStatus(object sender, MyEventArgs args)
{
if (this.InvokeRequired)
{
Thread.Sleep(2000);
this.Invoke(new EventHandler<MyEventArgs>(this.UpdateStatus), sender, args);
}
else
{
this._status.Text = args.NotificationText;
}
}
private readonly Label _status;
private readonly MyComponent _component = new MyComponent();
}
// Program entry point, runs event loop for the form that excercises out component
public static void Main(string[] args)
{
Control.CheckForIllegalCrossThreadCalls = true;
Application.EnableVisualStyles();
using (var form = new MyForm())
{
Application.Run(form);
}
}
}
}
As you can see, the code has 3 parts - first, the component that is using timer to call notification method every 500 milliseconds; second, a simple form with label and start/stop buttons; and finally main function to run the even loop.
You can deadlock the application by clicking start button and then within 2 seconds clicking stop button. However, the application is not "unfrozen" when I right-click on taskbar, sigh.
When I break into the deadlocked application, this is what I see when switched to the worker (timer) thread:
And this is what I see when switched to the main thread:
I would appreciate if you could try compiling and running this example; if it works the same for you as me, you could try updating the code to be more similar to what you have in your application and perhaps we can reproduce your exact issue. Once we reproduce it in a test application like this, it shouldn't be a problem to refactor it to make the problem go away (we would isolate essence of the problem).
[update 2]
I guess we agree that we can't easily reproduce your behaviour with the example I provided. I'm still pretty sure the deadlock in your scenario is broken by an extra even loop being introduced on right-click and this event loop processing messages pending from the notification callback. However, how this is achieved is beyond me.
That said I would like to make the following recommendation. Could you try these changes in your application and let me know if they solved the deadlock problem? Essentially, you would move ALL component code to worker threads (i.e. nothing that has to do with your component will be running on GUI thread any more except code to delegate to worker threads :-) )...
public void Start()
{
ThreadPool.QueueUserWorkItem(delegate // added
{
lock (this._lock)
{
if (!this._active)
{
this._active = true;
this._timer.Change(TimeSpan.FromMilliseconds(500d), TimeSpan.FromMilliseconds(-1d));
}
}
});
}
public void Stop()
{
ThreadPool.QueueUserWorkItem(delegate // added
{
lock (this._lock)
{
this._active = false;
}
});
}
I moved body of Start and Stop methods into a thread-pool worker thread (much like your timers call your callback regularly in context of a thread-pool worker). This means GUI thread will never own the lock, the lock will only be acquired in context of (probably different for each call) thread-pool worker threads.
Note that with the change above, my sample program doesn't deadlock any more (even with "Invoke" instead of "BeginInvoke").
[update 3]
As per your comment, queueing Start method is not acceptable because it needs to indicate whether the component was able to start. In this case I would recommend treating the "active" flag differently. You would switch to "int" (0 stopped, 1 running)and use "Interlocked" static methods to manipulate it (I assume that your component has more state it exposes - you would guard access to anything other than "active" flag with your lock):
public bool Start()
{
if (0 == Interlocked.CompareExchange(ref this._active, 0, 0)) // will evaluate to true if we're not started; this is a variation on the double-checked locking pattern, without the problems associated with lack of memory barriers (see http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html)
{
lock (this._lock) // serialize all Start calls that are invoked on an un-started component from different threads
{
if (this._active == 0) // make sure only the first Start call gets through to actual start, 2nd part of double-checked locking pattern
{
// run component startup
this._timer.Change(TimeSpan.FromMilliseconds(500d), TimeSpan.FromMilliseconds(-1d));
Interlocked.Exchange(ref this._active, 1); // now mark the component as successfully started
}
}
}
return true;
}
public void Stop()
{
Interlocked.Exchange(ref this._active, 0);
}
private void Notify(object ignore) // this will be invoked invoked in the context of a threadpool worker thread
{
if (0 != Interlocked.CompareExchange(ref this._active, 0, 0)) // only handle the timer event in started components (notice the pattern is the same as in Start method except for the return value comparison)
{
lock (this._lock) // protect internal state
{
if (this._active != 0)
{
var notification = this.Notification; // make a local copy
if (notification != null)
{
notification(this, new MyEventArgs { NotificationText = "Now is " + DateTime.Now.ToString("o") });
}
this._timer.Change(TimeSpan.FromMilliseconds(500d), TimeSpan.FromMilliseconds(-1d)); // rinse and repeat
}
}
}
}
private int _active;
A couple things come to mind when reviewing your code. The first thing is that you are not checking for a null delegate before firing the status event. If no listeners are bound to the event, then this will cause an exception, which if not caught or handled, might cause strange issues in threaded code.
So the first thing I'd so is this:
if(StatusEvent != null)
{
StatusEvent(this, new StatusEventArgs());
}
The other thing that comes to mind is that perhaps your lock is failing you in some manner. What type of object are you using for the lock? The simplest thing to use is just a plain ole "object", but you must ensure you are not using a value type (e.g. int, float, etc.) that would be boxed for locking, thus never really establishing a lock since each lock statement would box and create a new object instance. You should also keep in mind that a lock only keeps "other" threads out. If called on the same thread, then it will sail through the lock statement.
If you don't have the source for the GUI (which you probably should) you can use Reflector to disassemble it. There is even a plugin to generate source files so you could run the app in your VS IDE and set breakpoints.
Not having access to the GUI source makes this harder, but a general tip here... The WinForm GUI is not managed code, and doesn't mix well with .NET threading. The recommended solution for this is to use a BackgroundWorker to spawn a thread that is independent of the WinForm. Once you're running in the thread started by the BackgroundWorker, you're in pure managed code and you can use .NET's timers and threading for pretty much anything. The restriction is that you have to use the BackgroundWorker's events to pass information back to the GUI, and your thread started by the BackgroundWorker can't access the Winform controls.
Also, you'd be well off to disable the "Stop" button while the "Start" task is running, and vice versa. But a BackgroundWorker is still the way to go; that way the WinForm doesn't hang while the background thread is running.
Yes, this is a classic deadlock scenario. The StatusEvent cannot proceed because it needs the UI thread to update the controls. The UI thread is however stuck, trying to acquire the driverLock. Held by the code that calls StatusEvent. Neither thread can proceed.
Two ways to break the lock:
the StatusEvent code might not necessarily need to run synchronously. Use BeginInvoke instead of Invoke.
the UI thread might not necessarily need to wait for the thread to stop. Your thread could notify it later.
There is not enough context in your snippets to decide which one is better.
Note that you might have a potential race on the timer too, it isn't visible in your snippet. But the callback might run a microsecond after the timer was stopped. Avoid this kind of headache by using a real thread instead of a timer callback. It can do things periodically by calling WaitOne() on a ManualResetEvent, passing a timeout value. That ManualResetEvent is good to signal the thread to stop.
A wild guess here: Could the status message somehow be causing the other app to call your Stop task?
I would put debug stuff at the start of all three methods, see if you're deadlocking on yourself.
I want to display a progress bar while doing some work, but that would hang the UI and the progress bar won't update.
I have a WinForm ProgressForm with a ProgressBar that will continue indefinitely in a marquee fashion.
using(ProgressForm p = new ProgressForm(this))
{
//Do Some Work
}
Now there are many ways to solve the issue, like using BeginInvoke, wait for the task to complete and call EndInvoke. Or using the BackgroundWorker or Threads.
I am having some issues with the EndInvoke, though that's not the question. The question is which is the best and the simplest way you use to handle such situations, where you have to show the user that the program is working and not unresponsive, and how do you handle that with simplest code possible that is efficient and won't leak, and can update the GUI.
Like BackgroundWorker needs to have multiple functions, declare member variables, etc. Also you need to then hold a reference to the ProgressBar Form and dispose of it.
Edit: BackgroundWorker is not the answer because it may be that I don't get the progress notification, which means there would be no call to ProgressChanged as the DoWork is a single call to an external function, but I need to keep call the Application.DoEvents(); for the progress bar to keep rotating.
The bounty is for the best code solution for this problem. I just need to call Application.DoEvents() so that the Marque progress bar will work, while the worker function works in the Main thread, and it doesn't return any progress notification. I never needed .NET magic code to report progress automatically, I just needed a better solution than :
Action<String, String> exec = DoSomethingLongAndNotReturnAnyNotification;
IAsyncResult result = exec.BeginInvoke(path, parameters, null, null);
while (!result.IsCompleted)
{
Application.DoEvents();
}
exec.EndInvoke(result);
that keeps the progress bar alive (means not freezing but refreshes the marque)
It seems to me that you are operating on at least one false assumption.
1. You don't need to raise the ProgressChanged event to have a responsive UI
In your question you say this:
BackgroundWorker is not the answer
because it may be that I don't get the
progress notification, which means
there would be no call to
ProgressChanged as the DoWork is a
single call to an external function .
. .
Actually, it does not matter whether you call the ProgressChanged event or not. The whole purpose of that event is to temporarily transfer control back to the GUI thread to make an update that somehow reflects the progress of the work being done by the BackgroundWorker. If you are simply displaying a marquee progress bar, it would actually be pointless to raise the ProgressChanged event at all. The progress bar will continue rotating as long as it is displayed because the BackgroundWorker is doing its work on a separate thread from the GUI.
(On a side note, DoWork is an event, which means that it is not just "a single call to an external function"; you can add as many handlers as you like; and each of those handlers can contain as many function calls as it likes.)
2. You don't need to call Application.DoEvents to have a responsive UI
To me it sounds like you believe that the only way for the GUI to update is by calling Application.DoEvents:
I need to keep call the
Application.DoEvents(); for the
progress bar to keep rotating.
This is not true in a multithreaded scenario; if you use a BackgroundWorker, the GUI will continue to be responsive (on its own thread) while the BackgroundWorker does whatever has been attached to its DoWork event. Below is a simple example of how this might work for you.
private void ShowProgressFormWhileBackgroundWorkerRuns() {
// this is your presumably long-running method
Action<string, string> exec = DoSomethingLongAndNotReturnAnyNotification;
ProgressForm p = new ProgressForm(this);
BackgroundWorker b = new BackgroundWorker();
// set the worker to call your long-running method
b.DoWork += (object sender, DoWorkEventArgs e) => {
exec.Invoke(path, parameters);
};
// set the worker to close your progress form when it's completed
b.RunWorkerCompleted += (object sender, RunWorkerCompletedEventArgs e) => {
if (p != null && p.Visible) p.Close();
};
// now actually show the form
p.Show();
// this only tells your BackgroundWorker to START working;
// the current (i.e., GUI) thread will immediately continue,
// which means your progress bar will update, the window
// will continue firing button click events and all that
// good stuff
b.RunWorkerAsync();
}
3. You can't run two methods at the same time on the same thread
You say this:
I just need to call
Application.DoEvents() so that the
Marque progress bar will work, while
the worker function works in the Main
thread . . .
What you're asking for is simply not real. The "main" thread for a Windows Forms application is the GUI thread, which, if it's busy with your long-running method, is not providing visual updates. If you believe otherwise, I suspect you misunderstand what BeginInvoke does: it launches a delegate on a separate thread. In fact, the example code you have included in your question to call Application.DoEvents between exec.BeginInvoke and exec.EndInvoke is redundant; you are actually calling Application.DoEvents repeatedly from the GUI thread, which would be updating anyway. (If you found otherwise, I suspect it's because you called exec.EndInvoke right away, which blocked the current thread until the method finished.)
So yes, the answer you're looking for is to use a BackgroundWorker.
You could use BeginInvoke, but instead of calling EndInvoke from the GUI thread (which will block it if the method isn't finished), pass an AsyncCallback parameter to your BeginInvoke call (instead of just passing null), and close the progress form in your callback. Be aware, however, that if you do that, you're going to have to invoke the method that closes the progress form from the GUI thread, since otherwise you'll be trying to close a form, which is a GUI function, from a non-GUI thread. But really, all the pitfalls of using BeginInvoke/EndInvoke have already been dealt with for you with the BackgroundWorker class, even if you think it's ".NET magic code" (to me, it's just an intuitive and useful tool).
For me the easiest way is definitely to use a BackgroundWorker, which is specifically designed for this kind of task. The ProgressChanged event is perfectly fitted to update a progress bar, without worrying about cross-thread calls
There's a load of information about threading with .NET/C# on Stackoverflow, but the article that cleared up windows forms threading for me was our resident oracle, Jon Skeet's "Threading in Windows Forms".
The whole series is worth reading to brush up on your knowledge or learn from scratch.
I'm impatient, just show me some code
As far as "show me the code" goes, below is how I would do it with C# 3.5. The form contains 4 controls:
a textbox
a progressbar
2 buttons: "buttonLongTask" and "buttonAnother"
buttonAnother is there purely to demonstrate that the UI isn't blocked while the count-to-100 task is running.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void buttonLongTask_Click(object sender, EventArgs e)
{
Thread thread = new Thread(LongTask);
thread.IsBackground = true;
thread.Start();
}
private void buttonAnother_Click(object sender, EventArgs e)
{
textBox1.Text = "Have you seen this?";
}
private void LongTask()
{
for (int i = 0; i < 100; i++)
{
Update1(i);
Thread.Sleep(500);
}
}
public void Update1(int i)
{
if (InvokeRequired)
{
this.BeginInvoke(new Action<int>(Update1), new object[] { i });
return;
}
progressBar1.Value = i;
}
}
And another example that BackgroundWorker is the right way to do it...
using System;
using System.ComponentModel;
using System.Threading;
using System.Windows.Forms;
namespace SerialSample
{
public partial class Form1 : Form
{
private BackgroundWorker _BackgroundWorker;
private Random _Random;
public Form1()
{
InitializeComponent();
_ProgressBar.Style = ProgressBarStyle.Marquee;
_ProgressBar.Visible = false;
_Random = new Random();
InitializeBackgroundWorker();
}
private void InitializeBackgroundWorker()
{
_BackgroundWorker = new BackgroundWorker();
_BackgroundWorker.WorkerReportsProgress = true;
_BackgroundWorker.DoWork += (sender, e) => ((MethodInvoker)e.Argument).Invoke();
_BackgroundWorker.ProgressChanged += (sender, e) =>
{
_ProgressBar.Style = ProgressBarStyle.Continuous;
_ProgressBar.Value = e.ProgressPercentage;
};
_BackgroundWorker.RunWorkerCompleted += (sender, e) =>
{
if (_ProgressBar.Style == ProgressBarStyle.Marquee)
{
_ProgressBar.Visible = false;
}
};
}
private void buttonStart_Click(object sender, EventArgs e)
{
_BackgroundWorker.RunWorkerAsync(new MethodInvoker(() =>
{
_ProgressBar.BeginInvoke(new MethodInvoker(() => _ProgressBar.Visible = true));
for (int i = 0; i < 1000; i++)
{
Thread.Sleep(10);
_BackgroundWorker.ReportProgress(i / 10);
}
}));
}
}
}
Indeed you are on the right track. You should use another thread, and you have identified the best ways to do that. The rest is just updating the progress bar. In case you don't want to use BackgroundWorker like others have suggested, there is one trick to keep in mind. The trick is that you cannot update the progress bar from the worker thread because UI can be only manipulated from the UI thread. So you use the Invoke method. It goes something like this (fix the syntax errors yourself, I'm just writing a quick example):
class MyForm: Form
{
private void delegate UpdateDelegate(int Progress);
private void UpdateProgress(int Progress)
{
if ( this.InvokeRequired )
this.Invoke((UpdateDelegate)UpdateProgress, Progress);
else
this.MyProgressBar.Progress = Progress;
}
}
The InvokeRequired property will return true on every thread except the one that owns the form. The Invoke method will call the method on the UI thread, and will block until it completes. If you don't want to block, you can call BeginInvoke instead.
BackgroundWorker is not the answer because it may be that I don't get the progress notification...
What on earth does the fact that you're not getting progress notification have to do with the use of BackgroundWorker? If your long-running task doesn't have a reliable mechanism for reporting its progress, there's no way to reliably report its progress.
The simplest possible way to report progress of a long-running method is to run the method on the UI thread and have it report progress by updating the progress bar and then calling Application.DoEvents(). This will, technically, work. But the UI will be unresponsive between calls to Application.DoEvents(). This is the quick and dirty solution, and as Steve McConnell observes, the problem with quick and dirty solutions is that the bitterness of the dirty remains long after the sweetness of the quick is forgotten.
The next simplest way, as alluded to by another poster, is to implement a modal form that uses a BackgroundWorker to execute the long-running method. This provides a generally better user experience, and it frees you from having to solve the potentially complicated problem of what parts of your UI to leave functional while the long-running task is executing - while the modal form is open, none of the rest of your UI will respond to user actions. This is the quick and clean solution.
But it's still pretty user-hostile. It still locks up the UI while the long-running task is executing; it just does it in a pretty way. To make a user-friendly solution, you need to execute the task on another thread. The easiest way to do that is with a BackgroundWorker.
This approach opens the door to a lot of problems. It won't "leak," whatever that is supposed to mean. But whatever the long-running method is doing, it now has to do it in complete isolation from the pieces of the UI that remain enabled while it's running. And by complete, I mean complete. If the user can click anywhere with a mouse and cause some update to be made to some object that your long-running method ever looks at, you'll have problems. Any object that your long-running method uses which can raise an event is a potential road to misery.
It's that, and not getting BackgroundWorker to work properly, that's going to be the source of all of the pain.
I have to throw the simplest answer out there. You could always just implement the progress bar and have no relationship to anything of actual progress. Just start filling the bar say 1% a second, or 10% a second whatever seems similar to your action and if it fills over to start again.
This will atleast give the user the appearance of processing and make them understand to wait instead of just clicking a button and seeing nothing happen then clicking it more.
Here is another sample code to use BackgroundWorker to update ProgressBar, just add BackgroundWorker and Progressbar to your main form and use below code:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Shown += new EventHandler(Form1_Shown);
// To report progress from the background worker we need to set this property
backgroundWorker1.WorkerReportsProgress = true;
// This event will be raised on the worker thread when the worker starts
backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);
// This event will be raised when we call ReportProgress
backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged);
}
void Form1_Shown(object sender, EventArgs e)
{
// Start the background worker
backgroundWorker1.RunWorkerAsync();
}
// On worker thread so do our thing!
void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
// Your background task goes here
for (int i = 0; i <= 100; i++)
{
// Report progress to 'UI' thread
backgroundWorker1.ReportProgress(i);
// Simulate long task
System.Threading.Thread.Sleep(100);
}
}
// Back on the 'UI' thread so we can update the progress bar
void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// The progress percentage is a property of e
progressBar1.Value = e.ProgressPercentage;
}
}
refrence:from codeproject
Use the BackgroundWorker component it is designed for exactly this scenario.
You can hook into its progress update events and update your progress bar. The BackgroundWorker class ensures the callbacks are marshalled to the UI thread so you don't need to worry about any of that detail either.
Reading your requirements the simplest way would be to display a mode-less form and use a standard System.Windows.Forms timer to update the progress on the mode-less form. No threads, no possible memory leaks.
As this only uses the one UI thread, you would also need to call Application.DoEvents() at certain points during your main processing to guarantee the progress bar is updated visually.
Re: Your edit.
You need a BackgroundWorker or Thread to do the work, but it must call ReportProgress() periodically to tell the UI thread what it is doing. DotNet can't magically work out how much of the work you have done, so you have to tell it (a) what the maximum progress amount you will reach is, and then (b) about 100 or so times during the process, tell it which amount you are up to. (If you report progress fewer than 100 times, the progess bar will jump in large steps. If you report more than 100 times, you will just be wasting time trying to report a finer detail than the progress bar will helpfully display)
If your UI thread can happily continue while the background worker is running, then your work is done.
However, realistically, in most situations where the progress indication needs to be running, your UI needs to be very careful to avoid a re-entrant call. e.g. If you are running a progress display while exporting data, you don't want to allow the user to start exporting data again while the export is in progress.
You can handle this in two ways:
The export operation checks to see if the background worker is running, and disabled the export option while it is already importing. This will allow the user to do anything at all in your program except exporting - this could still be dangerous if the user could (for example) edit the data that is being exported.
Run the progress bar as a "modal" display so that your program reamins "alive" during the export, but the user can't actually do anything (other than cancel) until the export completes. DotNet is rubbish at supporting this, even though it's the most common approach. In this case, you need to put the UI thread into a busy wait loop where it calls Application.DoEvents() to keep message handling running (so the progress bar will work), but you need to add a MessageFilter that only allows your application to respond to "safe" events (e.g. it would allow Paint events so your application windows continue to redraw, but it would filter out mouse and keyboard messages so that the user can't actually do anything in the proigram while the export is in progress. There are also a couple of sneaky messages you'll need to pass through to allow the window to work as normal, and figuring these out will take a few minutes - I have a list of them at work, but don't have them to hand here I'm afraid. It's all the obvious ones like NCHITTEST plus a sneaky .net one (evilly in the WM_USER range) which is vital to get this working).
The last "gotcha" with the awful dotNet progress bar is that when you finish your operation and close the progress bar you'll find that it usually exits when reporting a value like "80%". Even if you force it to 100% and then wait for about half a second, it still may not reach 100%. Arrrgh! The solution is to set the progress to 100%, then to 99%, and then back to 100% - when the progress bar is told to move forwards, it animates slowly towards the target value. But if you tell it to go "backwards", it jumps immediately to that position. So by reversing it momentarily at the end, you can get it to actually show the value you asked it to show.
If you want a "rotating" progress bar, why not set the progress bar style to "Marquee" and using a BackgroundWorker to keep the UI responsive? You won't achieve a rotating progress bar easier than using the "Marquee" - style...
We are use modal form with BackgroundWorker for such a thing.
Here is quick solution:
public class ProgressWorker<TArgument> : BackgroundWorker where TArgument : class
{
public Action<TArgument> Action { get; set; }
protected override void OnDoWork(DoWorkEventArgs e)
{
if (Action!=null)
{
Action(e.Argument as TArgument);
}
}
}
public sealed partial class ProgressDlg<TArgument> : Form where TArgument : class
{
private readonly Action<TArgument> action;
public Exception Error { get; set; }
public ProgressDlg(Action<TArgument> action)
{
if (action == null) throw new ArgumentNullException("action");
this.action = action;
//InitializeComponent();
//MaximumSize = Size;
MaximizeBox = false;
Closing += new System.ComponentModel.CancelEventHandler(ProgressDlg_Closing);
}
public string NotificationText
{
set
{
if (value!=null)
{
Invoke(new Action<string>(s => Text = value));
}
}
}
void ProgressDlg_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
FormClosingEventArgs args = (FormClosingEventArgs)e;
if (args.CloseReason == CloseReason.UserClosing)
{
e.Cancel = true;
}
}
private void ProgressDlg_Load(object sender, EventArgs e)
{
}
public void RunWorker(TArgument argument)
{
System.Windows.Forms.Application.DoEvents();
using (var worker = new ProgressWorker<TArgument> {Action = action})
{
worker.RunWorkerAsync();
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
ShowDialog();
}
}
void worker_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
Error = e.Error;
DialogResult = DialogResult.Abort;
return;
}
DialogResult = DialogResult.OK;
}
}
And how we use it:
var dlg = new ProgressDlg<string>(obj =>
{
//DoWork()
Thread.Sleep(10000);
MessageBox.Show("Background task completed "obj);
});
dlg.RunWorker("SampleValue");
if (dlg.Error != null)
{
MessageBox.Show(dlg.Error.Message, "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
dlg.Dispose();
I've been working on a web crawling .NET app in my free time, and one of the features of this app that I wanted to included was a pause button to pause a specific thread.
I'm relatively new to multi-threading and I haven't been able to figure out a way to pause a thread indefinitely that is currently supported. I can't remember the exact class/method, but I know there is a way to do this but it has been flagged as obsolete by the .NET framework.
Is there any good general purpose way to indefinitely pause a worker thread in C# .NET.
I haven't had a lot of time lately to work on this app and the last time I touched it was in the .NET 2.0 framework. I'm open to any new features (if any) that exist in the .NET 3.5 framework, but I'd like to know of solution that also works in the 2.0 framework since that's what I use at work and it would be good to know just in case.
Never, ever use Thread.Suspend. The major problem with it is that 99% of the time you can't know what that thread is doing when you suspend it. If that thread holds a lock, you make it easier to get into a deadlock situation, etc. Keep in mind that code you are calling may be acquiring/releasing locks behind the scenes. Win32 has a similar API: SuspendThread and ResumeThread. The following docs for SuspendThread give a nice summary of the dangers of the API:
http://msdn.microsoft.com/en-us/library/ms686345(VS.85).aspx
This function is primarily designed for use by debuggers. It is not intended to be used for thread synchronization. Calling SuspendThread on a thread that owns a synchronization object, such as a mutex or critical section, can lead to a deadlock if the calling thread tries to obtain a synchronization object owned by a suspended thread. To avoid this situation, a thread within an application that is not a debugger should signal the other thread to suspend itself. The target thread must be designed to watch for this signal and respond appropriately.
The proper way to suspend a thread indefinitely is to use a ManualResetEvent. The thread is most likely looping, performing some work. The easiest way to suspend the thread is to have the thread "check" the event each iteration, like so:
while (true)
{
_suspendEvent.WaitOne(Timeout.Infinite);
// Do some work...
}
You specify an infinite timeout so when the event is not signaled, the thread will block indefinitely, until the event is signaled at which point the thread will resume where it left off.
You would create the event like so:
ManualResetEvent _suspendEvent = new ManualResetEvent(true);
The true parameter tells the event to start out in the signaled state.
When you want to pause the thread, you do the following:
_suspendEvent.Reset();
And to resume the thread:
_suspendEvent.Set();
You can use a similar mechanism to signal the thread to exit and wait on both events, detecting which event was signaled.
Just for fun I'll provide a complete example:
public class Worker
{
ManualResetEvent _shutdownEvent = new ManualResetEvent(false);
ManualResetEvent _pauseEvent = new ManualResetEvent(true);
Thread _thread;
public Worker() { }
public void Start()
{
_thread = new Thread(DoWork);
_thread.Start();
}
public void Pause()
{
_pauseEvent.Reset();
}
public void Resume()
{
_pauseEvent.Set();
}
public void Stop()
{
// Signal the shutdown event
_shutdownEvent.Set();
// Make sure to resume any paused threads
_pauseEvent.Set();
// Wait for the thread to exit
_thread.Join();
}
public void DoWork()
{
while (true)
{
_pauseEvent.WaitOne(Timeout.Infinite);
if (_shutdownEvent.WaitOne(0))
break;
// Do the work here..
}
}
}
The Threading in C# ebook summarises Thread.Suspend and Thread.Resume thusly:
The deprecated Suspend and Resume methods have two modes – dangerous and useless!
The book recommends using a synchronization construct such as an AutoResetEvent or Monitor.Wait to perform thread suspending and resuming.
If there are no synchronization requirements:
Thread.Sleep(Timeout.Infinite);
I just implemented a LoopingThread class which loops an action passed to the constructor. It is based on Brannon's post. I've put some other stuff into that like WaitForPause(), WaitForStop(), and a TimeBetween property, that indicates the time that should be waited before next looping.
I also decided to change the while-loop to an do-while-loop. This will give us a deterministic behavior for a successive Start() and Pause(). With deterministic I mean, that the action is executed at least once after a Start() command. In Brannon's implementation this might not be the case.
I omitted some things for the root of the matter. Things like "check if the thread was already started", or the IDisposable pattern.
public class LoopingThread
{
private readonly Action _loopedAction;
private readonly AutoResetEvent _pauseEvent;
private readonly AutoResetEvent _resumeEvent;
private readonly AutoResetEvent _stopEvent;
private readonly AutoResetEvent _waitEvent;
private readonly Thread _thread;
public LoopingThread (Action loopedAction)
{
_loopedAction = loopedAction;
_thread = new Thread (Loop);
_pauseEvent = new AutoResetEvent (false);
_resumeEvent = new AutoResetEvent (false);
_stopEvent = new AutoResetEvent (false);
_waitEvent = new AutoResetEvent (false);
}
public void Start ()
{
_thread.Start();
}
public void Pause (int timeout = 0)
{
_pauseEvent.Set();
_waitEvent.WaitOne (timeout);
}
public void Resume ()
{
_resumeEvent.Set ();
}
public void Stop (int timeout = 0)
{
_stopEvent.Set();
_resumeEvent.Set();
_thread.Join (timeout);
}
public void WaitForPause ()
{
Pause (Timeout.Infinite);
}
public void WaitForStop ()
{
Stop (Timeout.Infinite);
}
public int PauseBetween { get; set; }
private void Loop ()
{
do
{
_loopedAction ();
if (_pauseEvent.WaitOne (PauseBetween))
{
_waitEvent.Set ();
_resumeEvent.WaitOne (Timeout.Infinite);
}
} while (!_stopEvent.WaitOne (0));
}
}
Beside suggestions above, I'd like to add one tip. In some cases, use BackgroundWorker can simplify your code (especially when you use anonymous method to define DoWork and other events of it).
In line with what the others said - don't do it. What you really want to do is to "pause work", and let your threads roam free. Can you give us some more details about the thread(s) you want to suspend? If you didn't start the thread, you definitely shouldn't even consider suspending it - its not yours. If it is your thread, then I suggest instead of suspending it, you just have it sit, waiting for more work to do. Brannon has some excellent suggestions for this option in his response. Alternatively, just let it end; and spin up a new one when you need it.
The Suspend() and Resume() may be depricated, however they are in no way useless.
If, for example, you have a thread doing a lengthy work altering data, and the user wishes to stop it, he clicks on a button. Of course, you need to ask for verification, but, at the same time you do not want that thread to continue altering data, if the user decides that he really wants to abort.
Suspending the Thread while waiting for the user to click that Yes or No button at the confirmation dialog is the only way to prevent it from altering the data, before you signal the designated abort event that will allow it to stop.
Events may be nice for simple threads having one loop, but complicated threads with complex processing is another issue.
Certainly, Suspend() must never be used for syncronising, since its usefulness is not for this function.
Just my opinion.