How to create really unbreakable wpf busy window in separate thread?
Main thread run some a few second lasting intensive computation code. This code can not allow call UI refresh (DoEvents)(do not have cycle), and is not moveable to separate thread.
Busy Window have some spinner/progress, which should rotate/move. But it doesn't rotate/move if the main thread run intensive computation.
Most of "busy window in separate thread" - founded on web - do not work, if the main thread run intensive computation (nor Task, nor BackgroundWorker). Limitation is .net framework 4.0.
For testing, if I try to run intensive code in the main thread:
while(true) {}
then most web "busy window in separate thread" became blocked.
Best results I have with this code:
var thread = new Thread(new ThreadStart(() =>
{
SynchronizationContext.SetSynchronizationContext(
new DispatcherSynchronizationContext(
Dispatcher.CurrentDispatcher));
asyncCtl = creator();
asyncCtl.CreateControl();
asyncCtl.Show();
System.Windows.Threading.Dispatcher.Run();
}));
thread.SetApartmentState(ApartmentState.STA);
thread.IsBackground = true;
thread.Start();
Dispatcher.CurrentDispatcher.ShutdownStarted += CurrentDispatcher_ShutdownStarted;
Dispatcher.CurrentDispatcher.ShutdownFinished += CurrentDispatcher_ShutdownFinished;
When computation function finished, this code is called:
asyncCtl.Dispatcher.BeginInvokeShutdown(DispatcherPriority.Background);
But - events ShutdownStarted / ShutdownFinished are called on main thread exits. This seems to me too late.
If application run BusyWindow 10 times, these events are called 10 times on main thread exits.
I afraid if there are 10 times shown BusyWindow, there stay hang 10 non-shutdowned threads which ends lately - on main application exits.
So, how to correctly create and dispose such busy window?
Thanks.
Related
I've got code in a ViewModel that calls a service through a task.
When the task finishes, it'll populate an ObservableCollection.
The problem is that it's waiting on the task to finish by using the ContinueWith method and providing TaskScheduler.FromCurrentSynchronizationContext as task scheduler, so that the OC gets updated on the UI thread.
So far so good, but when it comes to unit testing, it throws an exception saying that "the current SynchronizationContext may not be used as a TaskScheduler."
If I use a mock SynchronizationContext on the unit test, then the ObservableCollection throws an error because it's being updated based from the dispatcher thread.
Is there any way to work around this?
Thanks.
It's not exactly easy, but it's not really that hard either. What you need to do is a spin up a worker Thread that's setup as STA and you start up the Dispatcher runtime on it. Once you have that worker sitting there you can dispatch work to it from the unit test threads which are, obviously, not initialized for this kind of work. So, first, here's how you startup the dispatcher thread in your test setup:
this.dispatcherThread = new Thread(() =>
{
// This is here just to force the dispatcher infrastructure to be setup on this thread
Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() =>
{
Trace.WriteLine("Dispatcher worker thread started.");
}));
// Run the dispatcher so it starts processing the message loop
Dispatcher.Run();
});
this.dispatcherThread.SetApartmentState(ApartmentState.STA);
this.dispatcherThread.IsBackground = true;
this.dispatcherThread.Start();
Now, if you want to cleanly shut that thread down in your test cleanup, which I recommend you do, you simply do the following:
Dispatcher.FromThread(this.dispatcherThread).InvokeShutdown();
So, all that infrastructure stuff out of the way, here's all you need to do in your test to execute on that thread.
public void MyTestMethod
{
// Kick the test off on the dispatcher worker thread synchronously which will block until the work is competed
Dispatcher.FromThread(this.dispatcherThread).Invoke(new Action(() =>
{
// FromCurrentSynchronizationContext will now resolve to the dispatcher thread here
}));
}
Add this to your test initialisation, to create a context:
SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
This makes it even simpler
TaskScheduler scheduler = Dispatcher.CurrentDispatcher.Invoke(TaskScheduler.FromCurrentSynchronizationContext)
you code can then use the scheduler explicitly (initialized with TaskScheduler.FromCurrentSynchronizationContext() during runtime)
I have a question about exception handling.
To prevent the "[YourProgram] has stopped working" Windows dialog, I usually catch even unhandled exceptions this way:
In App.xaml.cs:
protected override void OnStartup(StartupEventArgs e)
{
Application.Current.DispatcherUnhandledException += ProcessDispatcherException;
AppDomain.CurrentDomain.UnhandledException += ProcessUnhandledException;
// Blah blah blah... Performs a lot of loading operations...
mainWindow.Show();
}
and then
private void ProcessUnhandledException(object o, UnhandledExceptionEventArgs e)
{
logException("An unhandled exception has been thrown\n"+(e.ExceptionObject as Exception).ToString(), e.ExceptionObject as Exception);
Application.Current.Shutdown();
}
Okay, I don't have the Windows dialog. Now ideally I'd like to prevent this force closing scenario. The application I'm developing here has a startup time which lasts around 1 minute for the lightest users (most of them need to wait 2 or 3 minutes for launching it, it has to load a very large and complex data referential), so restarting it can cause trouble
I'd like to know about your "best practices" for this case. I am thinking about just re-creating a new window in the handler and re-show it anyway, so only the UI will be reinitialized to startup state, no other referential will be loaded, 2 - 3 minutes saved. Any other advices?
Oh and of course, this is the "extreme emergency case which should not be reached", but unfortunately it is, mostly due to our dependencies to other systems managed by other branches of the company with who I don't have any control or right to complain (yes, international companies can suck sometime), and it is not try/catchable in code :(
Thanks!
I am assuming from what you are writing that you want your application to be mission critical, meaning, if anything occurs that makes it fail, it needs to be restarted automatically.
The best way to accomplish this is to create a second watchdog process that will restart your application anytime it fails. You can then allow your application to quietly terminate itself when there is an unhandled exception, cleaning up whatever you can in your unhandled exception processor.
The simplest way to implement a watchdog like this is to have a no-window process (e.g., a console app) with a background thread loop that periodically checks that your application is running by checking if a wait handle is locked. Something like this:
// Declared in class
object checkLocker = new object();
bool mtStopCheck = false;
// Thread loop
bool stopCheck = false;
while (stopCheck == false)
{
if (wait_handle_is_unlocked)
restart_application();
Thread.Sleep(1000);
lock (checkLocker)
{
stopCheck = mtStopCheck;
}
}
When you want to shut the watchdog down another thread does this:
// Stop the watchdog thread so the watchdog app can shut down
lock (checkLocker)
{
mtStopCheck = true;
}
Since you'd be running in the same terminal session you don't need a global wait handle so no privilege issues on Vista/Windows 7.
If the user closes the application and you don't want it running again, you can send a signal to the watchdog process (e.g., with named pipes, or use a second kind of wait handle that you lock when you want the watchdog to suspend or shut down) that the app has been shut down and should not be restarted.
You can launch your watchdog in the startup folder or some other automatic method, or, you can have your app launch it the first time it runs.
Could someone shed some light on an issue I'm having?
I'm working on a wpf project. The scenario is as below:
I need to pop up a window(model window) on main UI thread and then close it. These works are started from another UI thread (to deter user from clicking on the main UI window.) then I close this window. The main code are displayed below. And it works.
As far as I know the close method would not get excuted before ShowDialog() returns (at least this is the case on UI thread, I mean code without dispatcher), does anyone have experience with multithread?
Window window;
private void Button_Click(object sender, RoutedEventArgs e)
{
Thread thread = new Thread(() =>
{
//create a window and let user work from this thread
//code is omitted.
//create another window on main UI thread
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
window = new Window();
window.ShowDialog();
}));
//do some work here
Thread.Sleep(1000);
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
//Thread.Sleep(1000);
window.Close();
}));
});
thread.Start();
}
Thank you for your time!
So if I understand your question correctly, you're saying that this code works exactly the way you want, but you're just trying to understand how (and why) it works?
Here's how it works. First, your thread runs this code:
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
window = new Window();
window.ShowDialog();
}));
That queues your action on the main (UI) thread's dispatcher queue, and then returns immediately: your worker thread continues running.
When the Application first started up (typically via the compiler-generated code that initializes your App.xaml object, though you can also do it explicitly by calling Application.Run), it started its message loop, which goes something like this (pseudocode, very very simplified):
public class Application {
public void Run() {
while (!Exited && action = Dispatcher.DequeueAction())
action();
}
}
So at some point shortly after you queue the action, the UI thread will get around to pulling your action off the queue and running it, at which point your action creates a window and shows it modally.
The modal window now starts its own message loop, which goes something like this (again, very simplified):
public class Window {
public bool? ShowDialog() {
DisableOtherWindowsAndShow();
while (!IsClosed && action = Dispatcher.DequeueAction())
action();
EnableOtherWindowsAndHide();
return DialogResult;
}
}
Later, your worker thread runs this code:
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
window.Close();
}));
Again, your action is queued to the UI thread's dispatcher queue, and then the BeginInvoke call returns immediately and your worker thread continues running.
So sooner or later, the UI thread's message loop will get around to dequeuing and executing your action, which tells the window to close. This has essentially the same effect as the user clicking the title bar's "X" button, which of course is perfectly OK to do even when you're inside a modal dialog. This causes ShowDialog's message loop to terminate (because the window is now closed), at which point the dialog is hidden and the other windows are re-enabled, ShowDialog returns, your original (ShowDialog) action is complete and so returns, and control falls back to the original message loop in Application.Run.
Note that there's one dispatcher queue per thread, not one per message loop. So your "close" action goes into the same queue that your "show dialog" action did. It's a different piece of code doing the message-loop polling now (the one inside ShowDialog instead of the one inside Application.Run), but the basics of the loop are the same.
BeginInvoke is a non-blocking method; it adds the action to the dispatcher queue, and doesn't wait for its completion. You should use Invoke instead, which calls the method synchronously on the dispatcher thread.
Title's about it. WPF app with some WCF stuff for IPC. I call Application.Current.Shutdown() and the app continues on happily. I thought Shutdown was supposed to be unstoppable.
Perhaps because it's being called from a background thread? Do I need to do some dispatcher fiddling?
You get an exception when I call Application.Current.Shutdown in any thread other than the main one, so I'd assume you where using "dispatcher fiddling" properly already.
In any case, this compiles and quits an application, so if the dispatcher bit doesn't look like what you have you could sling it in:
ThreadStart ts = delegate()
{
Dispatcher.BeginInvoke((Action)delegate()
{
Application.Current.Shutdown();
});
};
Thread t = new Thread(ts);
t.Start();
In my experience all threads have to either be terminated explicitly or be marked as background threads in order for the application to close.
Here is an example of kicking off a read thread in the background:
_readThread = new Thread(new ThreadStart(ReadThread));
_readThread.Name = "Receiver";
_readThread.Priority = ThreadPriority.Highest;
_readThread.IsBackground = true;
_readThread.Start();
The IsBackground property is the key. Without that being set, the thread won't terminate on when you call Shutdown.
I only experience Application.Current.Shutdown not working when I'm running from Visual Studio. Within Visual Studio (at least the 2010 version I'm using) Application.Current.Shutdown doesn't do a thing. If I single step through it executes this line and then continues. If I run the program (as an .exe) from Windows Explorer then Application.Current.Shutdown works fine.
There is probably an explanation for this since during debug other threads are active, but I can't explain it.
I have a windows form on the main thread and another thread that does some calculations. I'd like to update the status bar on my form from the work being done in the other thread. What's the best way to do this?
So far everything I've tried just makes things run really slowly. I'm using Visual Studio 2005.
You can use the marshaling techniques like Control.Invoke to execute a delegate on the UI thread where UI elements can be safely manipulated, but that approach is not very good. Actually, it is a terrible approach if all you want to do is update simple progress information.
By far the best method for doing this is:
Have your worker thread publish progress information to a shared variable.
Have your UI thread poll for it via a System.Windows.Forms.Timers on an interval that works well for you.
Here is what it might look like.
public class Example : Form
{
private volatile int percentComplete = 0;
private void StartThreadButton_Click(object sender, EventArgs args)
{
StatusBarUpdateTimer.Enabled = true;
new Thread(
() =>
{
for (int i = 1; i <= 100; i++)
{
DoSomeWork();
percentComplete = i;
}
}).Start();
}
private void StatusBarUpdateTimer_Tick(object sender, EventArgs args)
{
yourStatusBarPanel.Text = percentComplete.ToString() + "%";
StatusBarUpdateTimer.Enabled = percentComplete < 100;
}
}
This works well because:
The percentComplete field is declared 'volatile' ensuring its value can be reliably read from multiple threads.
The UI thread gets to dictate when and how often the UI gets updated...the way it should be!
The worker thread does not have to wait for a response from the UI thread before it can proceed as would be the case with Invoke.
It breaks the tight coupling between the UI and worker threads that Invoke would impose.
It is more efficient...considerably.
You get more throughput on both the UI and worker threads.
There is no chance of saturating the UI message queue as could be the case with BeginInvoke.
You do not have to litter you code with Invoke calls everytime you need to update the UI from the worker thread.
Make sure that you only update the user interface from the main thread or else you will have problems. You can switch your thread context by calling Invoke. There's a good post here on that.
You can send messages to the main thread and get it to update the progress bar, although you then need to check for the messages. You could also do the same sort of thing as a polling function.