When I call BuildCustomer.StartTask, I then call a method WriteToDatabase. Inside WriteToDatabase, I want to send a status back to the MainForm to write the status to the GUI. When the code reaches that point, my application freezes up and gives no error. I did find out that if I remove task.Wait(), it stops freezing and works. But I think I want the wait in because my BuildCustomer takes a bit of time and writes a lot of updates (including more updates from Common class) to the GUI. Can someone tell me what is wrong or what I should be doing differently? This is a .Net 4 project so I cannot use async, which I've seen other answers for.
public partial class MainForm : Window
{
public MainForm()
{
Common.SendMessage += UpdateStatus;
}
private void Button_Click(object sender, EventArgs e)
{
BuildCustomer.StartTask();
}
private void UpdateStatus(string message)
{
Dispatcher.Invoke(new Action(() =>
{
StatusTextBox.Text = message;
}));
}
}
public class BuildCustomer
{
public static void StartTask()
{
var action = new Action<object>(BuildCustomer);
var task = new Task(() => action(buildDetails));
task.Start();
task.Wait();
}
private void BuildCustomerDetails(object buildDetails)
{
Common.WriteToDatabase();
}
}
public class Common
{
public delegate void MessageLogDelegate(string message);
public static event MessageLogDelegate SendMessage;
public static void WriteToDatabase()
{
SendMessage("Some status message to write back to the GUI");
}
}
You have a deadlock. The StartTask waits on task.Wait() to complete but this occurs (is called on) on the calling thread which is the main UI thread.
The Task being waited eventually reaches UpdateStatus which calls an Invoke on the UI thread as well but this thread is currently waiting on task.Wait() (so it is blocking which results in the UI thread not being available indefinitely).
Try to add async keyword to method signature and use this:
await task;
It cause to does not sleep main thread(UI thread).
Related
I have a background task in my software which should run indefinitely.
The code repeating the task (and possibly other tasks in the future) looks like this:
public class RunTicketTasks
{
public async Task RunBackgroundTasks()
{
AssignTickets assignTickets = new AssignTickets();
while (true)
{
await assignTickets.AssignTicketCreator();
await Task.Delay(5 * 60 * 1000);
}
}
}
At the same time I have the WPF UI MainWindow.xaml which is the application entry point as far as I know.
within public MainWindow I start the task like the following way:
public MainWindow()
{
InitializeComponent();
JiraBackgroundTasks.RunTicketTasks ticketTasks = new JiraBackgroundTasks.RunTicketTasks();
ticketTasks.RunBackgroundTasks();
}
Apparently, this starts the task on the same thread (I believe). The task is started and running successfully, but the UI is beeing blocked due to long running operations. Meanwhile, when I uncomment the last line ticketTasks.RunBackgroundTasks(); the UI just runs fine.
How do I start the task in the background so that my User Interface is still responsive?
EDIT:
The reason I started the task this way was because of exception handling.
I can successfully start the task on a different thread as suggested with Task.Run(async () => await ticketTasks.RunBackgroundTasks()); But then I will not receive any exception if something goes wrong.
How can I start the task not blocking the UI and still receive the exception details if an exception is thrown?
The Internet states the following method:
await Task.Run(() => ticketTasks.RunBackgroundTasks());
But this will not work because The await operator can only be used within an async method.
One way to do it is to wrap the task in an async event callback:
public partial class MainWindow : Window
{
// I mocked your missing types, replace with your own
class AssignTickets
{
public Task AssignTicketCreator() => Task.CompletedTask;
}
public class RunTicketTasks
{
public async Task RunBackgroundTasks()
{
AssignTickets assignTickets = new AssignTickets();
int x = 0;
while (true)
{
await assignTickets.AssignTicketCreator();
await Task.Delay(1000);
var isRunningOnDispatcher = Application.Current.Dispatcher ==
System.Windows.Threading.Dispatcher.FromThread(Thread.CurrentThread);
Trace.WriteLine($"One second passed, running on dispatcher: {isRunningOnDispatcher}");
// exception will also get thrown on the main thread
if (x++ > 3) throw new Exception("Hello!");
}
}
}
public MainWindow()
{
InitializeComponent();
// event fires on UI thread!
this.Loaded += async (sender, args) =>
{
try
{
await new RunTicketTasks().RunBackgroundTasks();
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
};
}
}
I am trying to implement a long-running background process, that periodically reports on its progress, to update the UI in a UWP app. How can I accomplish this? I have seen several helpful topics, but none have all of the pieces, and I have been unable to put them all together.
For example, consider a user who picks a very large file, and the app is reading in and/or operating on the data in the file. The user clicks a button, which populates a list stored on the page with data from the file the user picks.
PART 1
The page and button's click event handler look something like this:
public sealed partial class MyPage : Page
{
public List<DataRecord> DataRecords { get; set; }
private DateTime LastUpdate;
public MyPage()
{
this.InitializeComponent();
this.DataRecords = new List<DataRecord>();
this.LastUpdate = DateTime.Now;
// Subscribe to the event handler for updates.
MyStorageWrapper.MyEvent += this.UpdateUI;
}
private async void LoadButton_Click(object sender, RoutedEventArgs e)
{
StorageFile pickedFile = // … obtained from FileOpenPicker.
if (pickedFile != null)
{
this.DataRecords = await MyStorageWrapper.GetDataAsync(pickedFile);
}
}
private void UpdateUI(long lineCount)
{
// This time check prevents the UI from updating so frequently
// that it becomes unresponsive as a result.
DateTime now = DateTime.Now;
if ((now - this.LastUpdate).Milliseconds > 3000)
{
// This updates a textblock to display the count, but could also
// update a progress bar or progress ring in here.
this.MessageTextBlock.Text = "Count: " + lineCount;
this.LastUpdate = now;
}
}
}
Inside of the MyStorageWrapper class:
public static class MyStorageWrapper
{
public delegate void MyEventHandler(long lineCount);
public static event MyEventHandler MyEvent;
private static void RaiseMyEvent(long lineCount)
{
// Ensure that something is listening to the event.
if (MyStorageWrapper.MyEvent!= null)
{
// Call the listening event handlers.
MyStorageWrapper.MyEvent(lineCount);
}
}
public static async Task<List<DataRecord>> GetDataAsync(StorageFile file)
{
List<DataRecord> recordsList = new List<DataRecord>();
using (Stream stream = await file.OpenStreamForReadAsync())
{
using (StreamReader reader = new StreamReader(stream))
{
while (!reader.EndOfStream)
{
string line = reader.ReadLine();
// Does its parsing here, and constructs a single DataRecord …
recordsList.Add(dataRecord);
// Raises an event.
MyStorageWrapper.RaiseMyEvent(recordsList.Count);
}
}
}
return recordsList;
}
}
The code for the time check I got from following this.
As written, this code makes the app unresponsive with a large file (I tested on a text file on the order of about 8.5 million lines). I thought adding async and await to the GetDataAsync() call would prevent this? Does this not do its work on a thread aside from the UI thread? Through Debug mode in Visual Studio, I have verified the program is progressing as expected... it is just tying up the UI thread, making the app unresponsive (see this page from Microsoft about the UI thread and asynchronous programming).
PART 2
I have successfully implemented before an asynchronous, long-running process that runs on a separate thread AND still updates the UI periodically... but this solution does not allow for the return value - specifically the line from PART 1 that says:
this.DataRecords = await MyStorageWrapper.GetDataAsync(pickedFile);
My previous, successful implementation follows (most of the bodies cut out for brevity). Is there a way to adapt this to allow for return values?
In a Page class:
public sealed partial class MyPage : Page
{
public Generator MyGenerator { get; set; }
public MyPage()
{
this.InitializeComponent();
this.MyGenerator = new Generator();
}
private void StartButton_Click(object sender, RoutedEventArgs e)
{
this.MyGenerator.ProgressUpdate += async (s, f) => await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, delegate ()
{
// Updates UI elements on the page from here.
}
this.MyGenerator.Start();
}
private void StopButton_Click(object sender, RoutedEventArgs e)
{
this.MyGenerator.Stop();
}
}
And in the Generator class:
public class Generator
{
private CancellationTokenSource cancellationTokenSource;
public event EventHandler<GeneratorStatus> ProgressUpdate;
public Generator()
{
this.cancellationTokenSource = new CancellationTokenSource();
}
public void Start()
{
Task task = Task.Run(() =>
{
while(true)
{
// Throw an Operation Cancelled exception if the task is cancelled.
this.cancellationTokenSource.Token.ThrowIfCancellationRequested();
// Does stuff here.
// Finally raise the event (assume that 'args' is the correct args and datatypes).
this.ProgressUpdate.Raise(this, new GeneratorStatus(args));
}
}, this.cancellationTokenSource.Token);
}
public void Stop()
{
this.cancellationTokenSource.Cancel();
}
}
Finally, there are two supporting classes for the ProgressUpdate event:
public class GeneratorStatus : EventArgs
{
// This class can contain a handful of properties; only one shown.
public int number { get; private set; }
public GeneratorStatus(int n)
{
this.number = n;
}
}
static class EventExtensions
{
public static void Raise(this EventHandler<GeneratorStatus> theEvent, object sender, GeneratorStatus args)
{
theEvent?.Invoke(sender, args);
}
}
It is key to understand that async/await does not directly say the awaited code will run on a different thread. When you do await GetDataAsync(pickedFile); the execution enters the GetDataAsync method still on the UI thread and continues there until await file.OpenStreamForReadAsync() is reached - and this is the only operation that will actually run asynchronously on a different thread (as file.OpenStreamForReadAsync is actually implemented this way).
However, once OpenStreamForReadAsync is completed (which will be really quick), await makes sure the execution returns to the same thread it started on - which means UI thread. So the actual expensive part of your code (reading the file in while) runs on UI thread.
You could marginally improve this by using reader.ReadLineAsync, but still, you will be returning to UI thread after each await.
ConfigureAwait(false)
The first trick you want to introduce to resolve this problem is ConfigureAwait(false).
Calling this on an asynchronous call tells the runtime that the execution does not have to return to the thread that originally called the asynchronous method - hence this can avoid returning execution to the UI thread. Great place to put it in your case is OpenStreamForReadAsync and ReadLineAsync calls:
public static async Task<List<DataRecord>> GetDataAsync(StorageFile file)
{
List<DataRecord> recordsList = new List<DataRecord>();
using (Stream stream = await file.OpenStreamForReadAsync().ConfigureAwait(false))
{
using (StreamReader reader = new StreamReader(stream))
{
while (!reader.EndOfStream)
{
string line = await reader.ReadLineAsync().ConfigureAwait(false);
// Does its parsing here, and constructs a single DataRecord …
recordsList.Add(dataRecord);
// Raises an event.
MyStorageWrapper.RaiseMyEvent(recordsList.Count);
}
}
}
return recordsList;
}
Dispatcher
Now you freed up your UI thread, but introduced yet another problem with the progress reporting. Because now MyStorageWrapper.RaiseMyEvent(recordsList.Count) runs on a different thread, you cannot update the UI in the UpdateUI method directly, as accessing UI elements from non-UI thread throws synchronization exception. Instead, you must use UI thread Dispatcher to make sure the code runs on the right thread.
In the constructor get reference to the UI thread Dispatcher:
private CoreDispatcher _dispatcher;
public MyPage()
{
this.InitializeComponent();
_dispatcher = Window.Current.Dispatcher;
...
}
Reason to do it ahead is that Window.Current is again accessible only from the UI thread, but the page constructor definitely runs there, so it is the ideal place to use.
Now rewrite UpdateUI as follows
private async void UpdateUI(long lineCount)
{
await _dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
// This time check prevents the UI from updating so frequently
// that it becomes unresponsive as a result.
DateTime now = DateTime.Now;
if ((now - this.LastUpdate).Milliseconds > 3000)
{
// This updates a textblock to display the count, but could also
// update a progress bar or progress ring in here.
this.MessageTextBlock.Text = "Count: " + lineCount;
this.LastUpdate = now;
}
});
}
I am using VSTO, and I would like to have a progress bar for a task that operates on the Excel model (getting and setting rages) via COM Interop. When doing any task that operates on the Excel model, it is very very highly recommended to only do so from the main thread (there are many posts that discuss this).
My problem is that I would like to have a progress bar (that exists on a secondary thread) and I would like to be able to start my task (on the main thread) when the progress bar loads. Is there some way to queue a function to execute on the main thread from a secondary thread? If not, is there some other way I can set this up?
My source is below:
abstract class BaseProgressTask
{
private ProgressForm _form;
public volatile bool CancelPending;
private void ShowProgressForm()
{
_form = new ProgressForm(this) { StartPosition = FormStartPosition.CenterScreen };
_form.ShowDialog();
}
public BaseProgressTask()
{
ThreadStart startDelegate = ShowProgressForm;
Thread thread = new Thread(startDelegate) { Priority = ThreadPriority.Highest };
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
}
public abstract void Run();
protected void ReportProgress(int percent)
{
_form.BeginInvoke(new Action(() => _form.SetProgress(percent)));
}
protected void CloseForm()
{
_form.BeginInvoke(new Action(() => _form.Close()));
}
}
public partial class ProgressForm : Form
{
private BaseProgressTask _task;
public ProgressForm(BaseProgressTask task)
{
InitializeComponent();
_task = task;
}
private void btnCancel_Click(object sender, EventArgs e)
{
_task.CancelPending = true;
lblStatus.Text = "Cancelling...";
}
public void SetProgress(int percent)
{
myProgressBar.Value = percent;
}
private void ProgressForm_Load(object sender, EventArgs e)
{
//Any way to do this?
ExecuteOnMainThread(_task.Run);
}
}
You may consider using the BackgroundWorker component instead. It executes an operation on a separate thread and allows to report a progress in a more convinient way using event handlers. See How to: Use a Background Worker and Walkthrough: Multithreading with the BackgroundWorker Component (C# and Visual Basic) for more information.
The SendMessage function from Windows API can be used to run an action on the main thread.
In case if your main thread is a form, you can handle it with this short code:
if (InvokeRequired)
{
this.Invoke(new Action(() => MyFunction()));
return;
}
or .NET 2.0
this.Invoke((MethodInvoker) delegate {MyFunction();});
I have created a simple form home and there is another file Mouse_Tracking.cs.
Mouse_Tracking.cs class is a thread class. I want to start and stop that thread using two different button click in home form.
How can I do this ?
Main form:
namespace computers
{
public partial class home : Form
{
public home()
{
InitializeComponent();
}
private void btn_start_Click(object sender, EventArgs e)
{
var mst = new Mouse_Tracking();
Thread thread1 = new Thread(new ThreadStart(mst.run));
thread1.Start();
}
private void btn_stop_Click(object sender, EventArgs e)
{
//Here I want to stop "thread1"
}
}
}
Computers class:
namespace computers
{
public class Mouse_Tracking
{
public void run()
{
// Some method goes here
}
}
You shouldn't kill threads from the outside. Instead, you should gently ask your thread to terminate, and in your thread you should respond to that request and return from the thread procedure.
You could use an event for that. E.g. add the following to your form class:
AutoResetEvent evtThreadShouldStop = new AutoResetEvent();
In your run method, check if the svtThreadShouldStop event is set every 0.1-1 seconds, if it’s set, return from the thread function, e.g. if( evtThreadShouldStop.WaitOne( 0 ) ) return;
And in your btn_stop_Click call evtThreadShouldStop.Set();
P.S. It’s rarely a good decision to create your own thread: creating and destroying threads is expensive. The runtime already has the thread pool you can use for your own background processing. To post your background task to a pool thread instead use e.g. ThreadPool.QueueUserWorkItem method. You can use same technique with AutoResetEvent to request task termination.
P.P.S. The name of the Mouse_Tracking class suggest you're trying to interact with mouse from the background thread? You can't do that: you can only interact with the GUI including mouse and keyboard from the GUI thread.
Here is an example of what Soonts has suggested. It's quite old-style solution but it's simple and will work fine. But there is a number of other approaches. You can use BackgroundWorker or TPL (Task class), each of which have own thread stop mechanisms.
And I believe that it's ok to create own thread without using existing thread pool if you don't need to do it too often.
public class Mouse_Tracking
{
private ManualResetEvent _stopEvent = new ManualResetEvent(false);
public void stop()
{
_stopEvent.Set();
}
public void run()
{
while (true)
{
if (_stopEvent.WaitOne(0))
{
//Console.WriteLine("stop");
// handle stop
return;
}
//Console.WriteLine("action!");
// some actions
Thread.Sleep(1000);
}
}
}
Sometimes its quite difficult to maintain the thread. You can achieve it by using BackgroundWorker class. You will get complete demonstration on how to use it is here Stop Watch Using Background Worker. I hope it will be useful.
You could use a class like this for controlling your thread(s):
class ThreadController {
private Thread _thread;
public void Start(ThreadStart start) {
if (_thread == null || !_thread.IsAlive) {
_thread = new Thread(start);
_thread.Start();
}
}
public void Stop() {
if (_thread != null && _thread.IsAlive) {
_thread.Interrupt(); // Use _thread.Abort() instead, if your thread does not wait for events.
_thread = null;
}
}
}
Then use:
public partial class home : Form
{
public home()
{
InitializeComponent();
_thread = new ThreadController();
}
private readonly ThreadController _thread;
private void btn_start_Click(object sender, EventArgs e)
{
var mst = new Mouse_Tracking();
_thread.Start(mst.run);
}
private void btn_stop_Click(object sender, EventArgs e)
{
_thread.Stop();
}
}
I tried to wrap the dispatcher in a thread. But the result is not what i expect. How can i solve that problem?
public void Start()
{
ThreadStart ts = inner;
Thread wrapper = new Thread(ts);
wrapper.Start();
}
private void inner()
{
_Runner.Dispatcher.Invoke(_Runner.Action, DispatcherPriority.Normal);
}
You have not shown us enough code/explained yourself well enough to be able to provide a good answer, but I'm guessing your action (_Runner.Action) is expensive and slow to execute. If so, that is why your UI is unresponsive. You're essentially telling the Dispatcher to run that expensive operation on the UI thread when what you really want to do is run as much of your operation on the background thread as possible, and then marshal back to the UI thread via the Dispatcher only when necessary.
When you fire an action through/on the dispatcher, that action is called on the UI thread.
My guess is that you are doing the work/processing in the _Runner.Action function and it is tying up the UI thread. You'll have to do the main processing part in the inner() function and then call the Dispatcher for the final update details.
If you absolutely must process on the dispatcher, break your process into smaller pieces and call Dispatcher.BeginInvoke() for each piece so other events can be processed in between your process.
You need to break Runner.Action into two parts - the long running part that does the calculation and the part that updates the GUI.
After you do that you call the long running part in the background thread and use the dispatcher only on the UI update part.
By the way, you should also probably use BeginInvoke and not Invoke.
If the long running part of Runner.Action is updating the GUI than you can't use a background thread to solve your problem - there are solutions for slow GUI operations but they change depending on what exactly you are trying to do.
Here is an example that will let you run WPF applications with multiple UI threads. I believe this will help you. Refer to this http://eprystupa.wordpress.com/2008/07/28/running-wpf-application-with-multiple-ui-threads/
Thread lThread = new Thread(() =>
{
var lWnd = new Window1();
lWnd.Show();
lWnd.Closed += (sender2, e2) => lWnd.Dispatcher.InvokeShutdown();
System.Windows.Threading.Dispatcher.Run();
});
lThread.SetApartmentState(ApartmentState.STA);
lThread.Start();
Ditto what everyone here has said.
Additionally, you may want to look into using the BackgroundWorker class.
This is what I have started using for background tasks... I have not been using it long, so I don't know if there are bugs.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace SSA.Utility
{
public class BackgroundTaskManager : IDisposable
{
private System.Windows.Threading.Dispatcher _OwnerDispatcher;
private System.Windows.Threading.Dispatcher _WorkerDispatcher;
private System.Threading.Thread _WorkerThread;
private Boolean _WorkerBusy;
private System.Threading.EventWaitHandle _WorkerStarted = new System.Threading.EventWaitHandle(false, System.Threading.EventResetMode.ManualReset);
public BackgroundTaskManager()
{
_OwnerDispatcher = System.Windows.Threading.Dispatcher.CurrentDispatcher;
_WorkerThread = new System.Threading.Thread(new System.Threading.ThreadStart(WorkerStart));
_WorkerThread.Name = "BackgroundTaskManager:" + DateTime.Now.Ticks.ToString();
_WorkerThread.IsBackground = true;
_WorkerThread.Start();
_WorkerStarted.WaitOne();
}
public Boolean IsBusy
{
get { return _WorkerBusy; }
}
public System.Windows.Threading.Dispatcher Dispatcher
{
get {
return _WorkerDispatcher;
}
}
public System.Windows.Threading.Dispatcher OwnerDispatcher
{
get
{
return _OwnerDispatcher;
}
}
private void WorkerStart()
{
_WorkerDispatcher = System.Windows.Threading.Dispatcher.CurrentDispatcher;
_WorkerDispatcher.Hooks.DispatcherInactive += WorkDone;
_WorkerDispatcher.Hooks.OperationPosted += WorkAdded;
_WorkerStarted.Set();
System.Windows.Threading.Dispatcher.Run();
}
private void WorkAdded(Object sender, System.Windows.Threading.DispatcherHookEventArgs e)
{
_WorkerBusy = true;
}
private void WorkDone(Object sender, EventArgs e)
{
_WorkerBusy = false;
}
public void Dispose()
{
if (_WorkerDispatcher != null)
{
_WorkerDispatcher.InvokeShutdown();
_WorkerDispatcher = null;
}
}
}
}
// Useage (not tested)
private SSA.Utility.BackgroundTaskManager _background = new SSA.Utility.BackgroundTaskManager();
public void LongTaskAsync()
{
_background.Dispatcher.BeginInvoke(new Action(LongTask), null);
}
public void LongTask()
{
System.Threading.Thread.Sleep(10000); // simulate a long task
_background.OwnerDispatcher.BeginInvoke(new Action<STATUSCLASS>(LongTaskUpdate), statusobject);
}
public void LongTaskUpdate(STATUSCLASS statusobject) {
}
Yes. _Runner.Action is the problem. Some long-timed methods used in the Dispatcher block. But solution is "dont use the any thread not related to UI in the dispatcher"