This question already has answers here:
Async method not running in parallel
(3 answers)
Closed 3 years ago.
The following seemingly simple scenario is causing me problems:
private List<Task> _Tasks = new List<Task>();
void someMethod() {
//stuff
prepareWork();
Task.WaitAll(_Tasks.ToArray());
//do more stuff
}
private void prepareWork() {
for (int i = 0; i < 2; ++i) {
_Tasks.Add(someWork());
//_Tasks.Add(Task.Run(() => someWork())); //<---- This does work
}
}
private async Task someWork() {
Thread.Sleep(2000);
}
I would expect someWork() to be run asynchronously, but it is not the case. It becomes the case when I replace the _Tasks.Add(someWork()); line with the commented line underneath. It seems to me I am missing something fundamental about the way C#/async and I would appreciate any help.
This is not the answer (and partially incorrect) but leaving as comment by Peter below add a
valid and overlooked point.
Will delete if Peter can put in an answer to the question
When you are adding tasks, you have just created the work to be done. But as you noticed it has not yet started.
_Tasks.Add(someWork());
To run any task you have to call its start method, to run all task in the list you can start them and then wait as you are doing for all to complete.
_task.ForEach(t=>t.Start());
Related
This question already has answers here:
Running multiple async tasks and waiting for them all to complete
(10 answers)
Closed 1 year ago.
I just started to touch the thread task of C#. I hope that whenever I click the button, I add a task, and then wait for all tasks to be completed before proceeding to the next step.
My code is as follows:
List<Task> SingleTaskList = new List<Task>();
private void Add_Click(object sender, RoutedEventArgs e)
{
Task t = Task.Factory.StartNew(() => { Dosomething();});
SingleTaskList.Add(Task.Factory.StartNew(() => { Dosomething(); }));
Task.Factory.ContinueWhenAll(SingleTaskList.ToArray(), tArray =>
{
Dispatcher.Invoke(() =>
{
//Update the UI
});
});
}
But I found that when any one of the tasks is completed, the next step will be taken.
How should I modify this code?
You can use Task.WhenAll like this:
await Task.WhenAll(SingleTaskList.ToArray());
Dispatcher.Invoke(() =>
{
//Update the UI
});
FYI: In order to use await there, your method will need to be marked as async or you will need to dispatch a new async task with the above statements.
There's quite a few issues with your code, and since it looks fundamentally broken I'll just answer your actual question: how to wait for multiple tasks and do something on the UI thread afterwards.
You want to use await and Task.WhenAll(), and so you need to mark your function as async. You want something like this:
private async void Add_Click(object sender, RoutedEventArgs e)
{
// fill SingleTaskList with whatever
await Task.WhenAll(SingleTaskList);
// update your UI here
// you're back on the GUI thread so no need for Dispatcher.Invoke
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
the question might be seems to be a regular one, but it isn't.
No matter what am I doing, the progress bar just not increasing.
In the base concept I have a GUI form and it has got a bacgroundworker. In the backgroundworker I am using a self defined class to read out the data from a measurement file. I want to increase the progress bar when it is done with one file, but no matter what am I doig it does nothing.
I have read the documentation but nothing.
https://learn.microsoft.com/en-us/dotnet/desktop/winforms/controls/how-to-set-the-value-displayed-by-the-windows-forms-progressbar-control?view=netframeworkdesktop-4.8
I have tried:
worker.ReportProgress method
Controls.Invoke((MethodInvoker)delegate{}); method
Furhtermore tried the Control.Update() and Control.Refress() too, but these are not working too.
Please help!
Thank you all in advance!
The reason the Progress bar won't update is that the UI cannot be updated from background threads. Backgroundworker runs on a background thread, which keeps the UI responsive.
Three solutions:
In the backgroundworker, start a new Task that runs on the Main UI thread, and update the progress bar there. This is bad coding, but there are other use cases where .InvokeRequired is valid.
Use backgroundworker ReportProgress. In the ProgressChanged handler (which runs on the UI thread), update the progressbar as normal.
Rewrite your app to use the "await Function1()/ async Task Fuction1() pattern instead of Backgroundworker. Here .InvokeRequired will likely be used. You can also use EventHandlers to return responses to the caller.
Examples Follow
#1 Warning bad coding style!
private void bgw1_DoWork(Object sender, DoWorkEventArgs e)
{
...
await Task.Run( () =>
{
progressBar1.InvokeIfRequired( o =>
{
progressBar1.Value += 1;
} );
});
...
}
public static class MyExtensions
{
public static void InvokeIfRequired<T>(this T obj, InvokeIfRequiredDelegate<T> action) where T : ISynchronizeInvoke
{
if (obj.InvokeRequired)
{
obj.Invoke(action, new Object[] { obj });
}
else
{
action(obj);
}
}
}
#2 This way works well:
private void bgw1_DoWork(Object sender, DoWorkEventArgs e)
{
...
worker.ReportProgress(0, 50); //50% progress out of 100
...
}
private void bgw1_ProgressChanged(Object sender, ProgressChangedEventArgs e)
{
if(e.UserState is Int32 i)
{
progressBar1.Value = i;
}
}
#3
Is a complete re-write and likely outside the scope of your question.
Remember to mark this as an answer if it helps you.
This question already has answers here:
An async/await example that causes a deadlock
(5 answers)
Closed 4 years ago.
I know there are quite a lot of Post about Task deadlocks, but I simply can't find the right sollution.
So I basically have this setup:
public event EventHandler StateChangedEvent;
public bool Busy
{
...
set
{
...
this.StateChangedEvent?.Invoke(this, EventArgs.Empty)
}
}
public void Main()
{
...
this.StateChangedEvent += this.OnStateChangedEvent;
}
public void OnStateChangedEvent(object sender, EventArgs e)
{
this.TextBox.Invoke(() => this.TextBox.Text = "Change");
this.Invoke(() => this.Cursor = Cursors.WaitCursor);
}
public void ButtonAction_Click(object sender, EventArgs e) //actually part of an API with an virtal - override method on between. Can't change here to async
{
...
Task.Run(async () => await this.AsyncDoStuff()).Wait();
... // Synchron stuff needs to be done afterwards
}
public async Task AsyncDoStuff()
{
this.Busy = true; //Causes Deadlock
await Stuff1();
await Stuff2();
}
So in reality those calls are split among different classes, but the basic structure remains. Yes I know I should go async all the way up, but let's say the first ButtonAction_Click is part op an API/Framework and can't be changed to async.
I know the reason is because I block the UI Thread and then access it again...So what is the best solution for this?
Thanks in advance!
So from your other comments it sounds like the code in ButtonAction_Click is outside your control and you can't change it. Unfortunately, that's where the problem is - this event handler is totally blocking the UI thread until the work has finished. There's no way to unblock the thread.
Your only recourse is to avoid any blocking interactions with the UI thread.
The following code from your example is definitely going to cause deadlock, because Invoke() will block until the UI (which is already blocked) responds:
this.TextBox.Invoke(() => this.TextBox.Text = "Change");
this.Invoke(() => this.Cursor = Cursors.WaitCursor);
You could try using BeginInvoke() instead of Invoke(), but the unfortunate consequence is that these UI changes won't actually execute until the UI thread is unblocked, and by then your background work is already finished. It might fix your deadlock, though.
This question already has answers here:
thread get 100% CPU very fast
(5 answers)
Closed 4 years ago.
I have a task to get a piece of c# code to make my CPU go 100% consistently. I have tried infinite loops, big integer calculations, concatenation of numerous very long strings.... everything either goes to 100% for a few moments and then down to like 60% or doesn't go to 100% at all.
Is there a simple piece of code that can achieve this?
Also using Windows 10
You would want to implement threading for this as was previously stated. Your thread would call a method that contains a while(true) loop. For example:
Random rand = new Random()
List<Thread> threads = new List<Thread>();
public void KillCore()
{
long num = 0;
while(true)
{
num += rand.Next(100, 1000);
if (num > 1000000) { num = 0; }
}
}
public void Main()
{
while (true)
{
threads.Add( new Thread( new ThreadStart(KillCore) ) );
}
}
You don't have to add the threads to a list but you may want to if you somewhere down the road want to call Thread.Abort() to kill them off. To do this you would need a collection of some sort to iterate through and call the Abort() method for every Thread instance in the collection. The method to do that would look as follows.
public void StopThreads()
{
foreach (Thread t in threads) { t.Abort(); }
}
use parallel for to maximize the CPU Cores usage and get the best of threading , inside each thread create an infinite loop using while(true) and congratulations
you have **** your CPU :D
This question already has answers here:
Not updating GUI in time
(2 answers)
WinForm Application UI Hangs during Long-Running Operation
(3 answers)
Accessing UI controls in Task.Run with async/await on WinForms
(6 answers)
Closed 5 years ago.
I have a function which makes process. At the beginning of the function I want to change the text of a label which indicates the state, and once the process ends, change it again.
The fact is that only is shown the final change.
I know I can make a thread for the process but not needed in this case and I merely want to know if there's some tip or trick to accomplish it whitout the use of a thread.
In this case When you change something in UI it does not change until the whole process is completed so as you said you can only see the final state of your label. The trick is simple. You need to use a secondary thread while you are going to update the label for the fist time.
Look at the example below :
class Program
{
private delegate void del();
static void Main(string[] args)
{
del d = updateConsole;
var res = d.BeginInvoke(null, null);
while (!res.IsCompleted)
{
// do the job here
}
d.EndInvoke(res);
Thread.Sleep(1000);
Console.Clear();
Console.WriteLine("Done!");
Console.Read();
}
private static void updateConsole()
{
for (var i = 0; i <= 10; i++)
{
Thread.Sleep(500);
Console.Clear();
Console.WriteLine(i);
}
}
}
This simple technique helps you to separate the first update of the label from the whole process.