I have a logic on form load which is using parallel library, that is working fine. but after executing the tasks it is not opening the form. Can anyone help on this?
private void Form1_Load(object sender, EventArgs e)
{
Task[] tasks = new Task[3];
var scheduler = TaskScheduler.FromCurrentSynchronizationContext();
dummyList.ForEach(d =>
{
tasks[d] =
Task.Factory.StartNew(() =>
{
ProcessPage();
}, CancellationToken.None,
TaskCreationOptions.None,
TaskScheduler.FromCurrentSynchronizationContext());
});
Task.WaitAll(tasks);
Form2 frm = new Form2();
frm.Show();
}
It's pretty simple, you're deadlocking yourself.
You're instructing the tasks to run on the current synchronization context, which is your UI thread, via TaskScheduler.FromCurrentSynchronizationContext().
Then, you Wait on the main thread, synchronously blocking it.
Instead, you can asynchronously wait:
private async void Form1_Load(object sender, EventArgs e)
{
var tasks = dummyList.Select(() => Task.Run(() => ProcessPage());
await Task.WhenAll(tasks);
var form = new Form2();
form.Show();
}
One of your tasks is probably stuck. Nothing will appear until all the tasks have completed due to your WaitAll()
Related
I've seen many of these types of questions asked and answered here but none of those seems to solve my problem.
I have a Page that retrieves and shows a list of data from a database. my initial code looked like this
private void HistoryPage_OnLoaded(object sender, RoutedEventArgs e)
{
//''''''
_invoices = Invoice.GetAll(); // returns a list of invoices
InvoiceList = new PagingCollection<Invoice>(_invoices, _itemsPerPage);
DgInvoices.ItemsSource = InvoiceList.CurrentItems;
//'''''''''
}
this worked ok until the data list got bigger. now it takes about 6-8 seconds for this operation.
then I tried to fetch data from a different thread and update the Datagrid ( DGInvoices ) from there.
private void HistoryPage_OnLoaded(object sender, RoutedEventArgs e)
{
//''''''''
new Thread(() =>
{
_invoices = Invoice.GetAll();
InvoiceList = new PagingCollection<Invoice>(_invoices, _itemsPerPage);
DgInvoices.ItemsSource = InvoiceList.CurrentItems;
}).Start();
}
which throws this exception
The Calling thread cannot access this object because a different thread owns it
After searching around, I found that the Dispatcher is the way to go about this. but I cannot get it to work.
private void HistoryPage_OnLoaded(object sender, RoutedEventArgs e)
{
//''''''''
new Thread(() =>
{
_invoices = Invoice.GetAll();
InvoiceList = new PagingCollection<Invoice>(_invoices, _itemsPerPage);
Dispatcher.Invoke(() =>
{
DgInvoices.ItemsSource = InvoiceList.CurrentItems;
});
}).Start();
}
this still throws the above exception.
can you recommend a way to get this working?
I personally think a BackgroundWorker would be the best option. Dispatcher may work, but it's a more "forced" operation in WPF and it can sometimes present a litany of other problems. With a BackgroundWorker you can do your data work in the background, and then do your UI work on the main thread upon its completion.
As an example:
BackgroundWorker bw = new BackgroundWorker();
public MainWindow()
{
InitializeComponent();
//Subscribe to the events
bw.DoWork += Bw_DoWork;
bw.RunWorkerCompleted += Bw_RunWorkerCompleted;
}
private void HistoryPage_OnLoaded(object sender, RoutedEventArgs e)
{
//Start background worker on page load
bw.RunWorkerAsync(); //This is the DoWork function
}
//Background worker executes on separate thread
private void Bw_DoWork(object sender, DoWorkEventArgs e)
{
//Do long running operations
_invoices = Invoice.GetAll();
}
//Fires when the DoWork operation finishes. Executes on the main UI thread
private void Bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//Update UI when the worker completes on the main thread
InvoiceList = new PagingCollection<Invoice>(_invoices, _itemsPerPage);
DgInvoices.ItemsSource = InvoiceList.CurrentItems;
}
If your operation gets really long you can even tap into the BackgrounWorker.ReportProgess operation and give status updates to the UI. It's a great tool for loading operations that you can use to avoid locking the UI.
Why are you using Dispatcher within new thread?
You can simply use Dipatcher outside of the new thread.
Like this:
Dispatcher.Invoke(() =>
{
DgInvoices.ItemsSource = InvoiceList.CurrentItems;
});
So you can invoke on the main thread and not on the new thread
Don't update DgInvoices.ItemsSource directly inside the thread.
Instead bind ItemSource to a property and update the property in the thread.
Upon to your last edit, to get this working you must move
InvoiceList = new PagingCollection<Invoice>(_invoices, _itemsPerPage) to the Dispatcher too because its child CurrentItems is assigned to DitaGrid's items source. Thus, you cannot modify InvoiceList from other than main UI thread.
Additionally I suggest using Task instead of Thread because creating thread is too expensive operation and Task may reuse already created threads and save your time and PCs resources. Task is a smart wrapper of the Thread.
private void HistoryPage_OnLoaded(object sender, RoutedEventArgs e)
{
//''''''''
Task.Run(() =>
{
_invoices = Invoice.GetAll();
Dispatcher.Invoke(() =>
{
InvoiceList = new PagingCollection<Invoice>(_invoices, _itemsPerPage);
DgInvoices.ItemsSource = InvoiceList.CurrentItems;
});
});
}
Or in case your API have async method to get the data you may use asynchronuous approach. But i dont's know if such awaitable method exists.
private async void HistoryPage_OnLoaded(object sender, RoutedEventArgs e)
{
//''''''''
await _invoices = Invoice.GetAllAsync();
InvoiceList = new PagingCollection<Invoice>(_invoices, _itemsPerPage);
DgInvoices.ItemsSource = InvoiceList.CurrentItems;
}
Instead of working in the background - this code still freeze my program:
private void button_Click(object sender, RoutedEventArgs e)
{
this.Dispatcher.BeginInvoke(new Action(() =>
{
Thread.Sleep(5000);
label.Content = "Done";
}), DispatcherPriority.Normal);
}
I have tried with Thread/Tasks, thread example:
private void button_Click(object sender, RoutedEventArgs e)
{
var t = new Thread(new ThreadStart(runtask));
t.Start();
}
private void runtask()
{
this.Dispatcher.BeginInvoke(new Action(() =>
{
Thread.Sleep(5000);
label.Content = "Done";
}), DispatcherPriority.Normal);
}
Task example:
private void button_Click(object sender, RoutedEventArgs e)
{
Task.Run(() =>
{
Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new Action(() =>
{
Thread.Sleep(5000);
label.Content = "Done";
}));
});
}
And still my program is freezing. Any suggestions?
From the documentation of the Dispatcher class:
Provides services for managing the queue of work items for a thread.
From the documentation of Dispatcher.BeginInvoke:
Executes the specified delegate asynchronously with the specified arguments on the thread that the Dispatcher was created on.
Here "asynchronously" refers to the secondary thread, not the main one. Because the main one is owned by the main Dispatcher. That means that every call of Invoke or BeginInvoke on that Dispatcher, from whatever Thread, will put the invoked Action in the queue of operations that the main Thread must execute, but from the point of view of the main Thread they will be executed synchronously, one after the other.
For example, if you put 3 Action like Thread.Sleep(1000); within 10 ms on the Dispatcher, whether with Invoke or BeginInvoke and from whether Thread, that Dispatcher will make the UI Thread to execute the 3 Action synchronously, so they will take a total of 3000 ms.
Maybe the documentation about BeginInvoke could have been written better, like:
Executes the specified delegate with the specified arguments on the thread that the Dispatcher was created on. The specified delegate is executed asynchronously from the point of view of the calling thread.
Now... Invoke or BeginInvoke?
Using Invoke, the secondary Thread is saying to the Dispatcher: let's execute this on the main Thread, and don't dare to return until your thread's job has finished. Then and only then I will continue.
For example, if you write this:
this.Dispatcher.Invoke(new Action(() =>
{
Thread.Sleep(5000);
Debug.WriteLine("After Sleep");
}));
Debug.WriteLine("Continuation on secondary Thread");
The Console will print after ~ 5000 ms:
"After Sleep"
"Continuation on secondary Thread"
Using BeginInvoke, instead, the Thread is saying: "hey, Dispatcher, queue this operation on the main Thread, but return as soon as possible so I can continue my job immediately".
In this case the Console will print immediately:
"Continuation on secondary Thread"
And after ~ 5000 ms:
"After Sleep"
Now, if your purpose is to execute some heavy operation on the background, you should learn about the async/await pattern, available from .NET 4.5 and C# 5.0.
In your example, I would write:
private async void button_Click(object sender, RoutedEventArgs e)
{
await Task.Delay(5000); // await a heavy operation executed in background
label.Content = "Done"; // control back to the UI Thread that executes this
}
You can use this small extension if your UI access is the last of your method.
https://mitsufu.wordpress.com/2015/08/03/dispatcher-switchto/
private void Button_Click(object sender, RoutedEventArgs e)
{
Task.Run(async () =>
{
//heavy background operation
await Dispatcher.SwitchTo();
Title = "ok";
});
}
I have a windows forms application. I want to do something in background after pressing some button.
//---------- MyWorker::Run
public Task Run()
{
WorkerTask = Task.Factory.StartNew(() =>
{
//Access MyWorker's properties etc. causes complications as it runs from
// a different thread and I need to use InvokeRequired etc. but not everything has Invoke method implemented.
}, TokenSource.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
return WorkerTask;
}
//---------- Form event
async void DoSomething(object sender, EventArgs e)
{
var task = MyWorker.Run();
await task;
}
However there are some complications when I try to access MyWorker's objects in the run method as it runs in a different thread. What pattern would be prefered here? I was thinking about something like:
//---------- Form event
async void DoSomething(object sender, EventArgs e)
{
Task.Factory.StartNew(() =>
{
var MyWorker1 = new MyWorker(...);
// Worker is synchronous here
MyWorker1.Run();
}, TokenSource.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
}
But I wouldn't be able to access MyWorker from other methods. Thanks in advance .. I'm confused.
You shouldn't implement a method entirely in terms of Task.Run (or StartNew); instead, call the method with Task.Run:
async void DoSomething(object sender, EventArgs e)
{
var task = Task.Run(() => MyWorker.Run());
await task;
}
This way you can access MyWorker from multiple methods... and multiple threads, of course. It's up to you to apply appropriate synchronization then.
On a side note, you shouldn't ever need to use Invoke or BeginInvoke in modern apps; there are always superior solutions. For example, await will return to the UI thread context automatically. Similarly, Progress<T> can synchronize to the UI context automatically.
You can customize this approach:
var myTasks = new ConcurrentBag<Task>();
var myResults = new ConcurrentBag<int>();
and use it like:
myTasks.Add(Task.Factory.StartNew(() =>
{
//do something
myResults.Add(5);
});
I created a Thread that executes a task, but i need to pause my Main thread until my secondary threads ends the task.
private void AquilesPL_Load(object sender, EventArgs e)
{
ThreadStart ts = new ThreadStart(RunTask)
Thread t = new Thread(ts);
t.Start();
SomeFunction1();
SomeFunction2();
//I need to pause the main thread here, if runtask() continue working
//if runt task ends, this main thread must to continue.
ReadFile();
CloseProgram();
}
private void RunTask()
{
//Some code that write a file
//RunTaskfunction ends, and i have to continue
}
private void ReadFile()
{
//Reading the file, this file has been written by RunTask
}
Thanks in advance.
but i need to pause my Main thread until my secondary threads ends the task.
This is typically a bad idea. A better solution is to disable the UI while the task is executing, then re-enable it when it's completed.
The TPL and async/await make this fairly straightforward. For example:
private async void AquilesPL_Load(object sender, EventArgs e)
{
var task = Task.Run(() => RunTask());
SomeFunction1();
SomeFunction2();
// Disable your UI controls
await task; // This will wait until the task completes,
// but do it asynchronously so it does not block the UI thread
// This won't read until the other task is done
ReadFile();
// Enable your UI controls here
}
If you can't use C# 5, you can do this via .NET 4 and the TPL:
private void AquilesPL_Load(object sender, EventArgs e)
{
var task = Task.Factory.StartNew(() => RunTask());
SomeFunction1();
SomeFunction2();
// Disable your UI controls
task.ContinueWith(t =>
{
// This won't read until the other task is done
ReadFile();
// Enable your UI controls here
}, TaskScheduler.FromCurrentSynchronizationContext());
}
I was following an example from C# in a Nutshell. According to the text the following code is supposed to be non blocking, but I find that the form will not display until the 5 seconds have passed.
private void Form1_Load(object sender, EventArgs e)
{
var tcs = new TaskCompletionSource<int>();
new Thread(() => {Thread.Sleep(5000); tcs.SetResult(42); }).Start();
Task<int> task = tcs.Task;
MessageBox.Show(task.Result.ToString());
}
I have a feeling it's something to do with Thread.Sleep() and instead of putting the new Thread to sleep, it's putting the main Thread to sleep.
Why is it blocking the UI thread?
When you are trying to get result of task task.Result main thread will be blocked until task will finish it's execution (i.e. result will be available). Use task.ContinueWith if you don't want to wait for async operation completion:
Task<int> task = tcs.Task;
task.ContinueWith(t => {
MessageBox.Show(t.Result.ToString());
});
BTW there is nice feature in .NET 4.5 for resuming suspended operation when task is completed - async methods:
private async void Form1_Load(object sender, EventArgs e)
{
var tcs = new TaskCompletionSource<int>();
new Thread(() => { Thread.Sleep(2000); tcs.SetResult(42); }).Start();
int result = await tcs.Task;
MessageBox.Show(result.ToString());
}
This method will yield control to caller immediately after starting to wait for task result. When result will be available, method will continue execution and show message.
Actually as #Servy pointed in comments, async method which return void is not very good practice (e.g. for error handling), but sometimes it's OK to use them for event handlers.
When you call Task.Result.ToString() (in the MessageBox.Show) the Task class has a mechanism that waits for the task to be finished before actually giving you the result (as it doesn't actually have it until the Task finishes. Here's my proof:
private void Form1_Load(object sender, EventArgs e)
{
var tcs = new TaskCompletionSource<int>();
new Thread(() => {Thread.Sleep(5000); tcs.SetResult(42); }).Start();
Task<int> task = tcs.Task;
Thread.Sleep(2500);
MessageBox.Show("Waited for 2.5secs on UI thread.");
MessageBox.Show(task.Result.ToString());
}
You will see that it shows you the 2.5sec message box before the messagebox with 42. (in fact, 2.5 seconds before that).
What you are looking for is this:
private void Form1_Load(object sender, EventArgs e)
{
var tcs = new TaskCompletionSource<int>();
new Thread(() => {Thread.Sleep(5000); tcs.SetResult(42); }).Start();
Task<int> task = tcs.Task;
task.ContinueWith(t => MessageBox.Show(t.Result.ToString()));
}
This will not freeze the UI thread.