Task.WaitAll() not working as expected - c#

I'm trying to figure out how to work with the Task class. In the past I have always used the regular Thread class, but I'm trying to grasp all of the asynchronous programming...
As an example, I created a main Winforms application that has all the code.
The relevant code for my problem is:
//Relevant delegates
public delegate void MethodAction(int num);
public delegate void MethodConversion();
public delegate void OnCompletionAction(string completiontext);
//Button user presses
private void button4_Click(object sender, EventArgs e)
{
richTextBox1.Clear();
sw.Reset();
sw.Start();
Sync.RunAsync3(calcSim);
}
//The method that simulates a calculation by adding a sleep
//the input param threadlength is just to allow threads to take longer than others
//since I'm multithreading, I have to invoke the writing code on the windows RichTextbox control
private void calcSim(int threadlength)
{
string threadname = Thread.CurrentThread.Name;
for (int i = 0; i < 10; i++) //Thread calc should take 3s
{
Thread.Sleep(300 + threadlength);
richTextBox1.Invoke((MethodConversion)(() =>
{
richTextBox1.AppendText(string.Format("Thread: {0}\tVersion: {1}\n", threadname, (i + 1).ToString()));
}));
}
}
//Class that contains the different processing methods
public static class Sync
{
public static event OnCompletionAction OnProcCompletion;
public static void RunAsync3(MethodAction doM)
{
Task[] t = new Task[4];
for(int i = 0; i < 4; i++)
{
t[i] = Task.Factory.StartNew((Action)(() => { doM(50 * i); }));
}
Task.WaitAll(t);
if (OnProcCompletion != null) OnProcCompletion("RunSync method finished");
}
}
The problem lies within Task.WaitAll(t)... For some reason, which I can't figure out, it completely blocks on that line and doesn't respond anymore. If I omit that line, the form gets updated in realtime and the execution take about 3 seconds.
My question is: why isn't Task.WaitAll() blocking the UI thread for 3 seconds before releasing it and allowing the rest of the code to execute?
I know it should be blocking the UI for some time (until all threads are calculated), but it blocks the complete app endlessly. It seems to be waiting forever?
EDIT
I've been suggested to use WhenAll instead of WaitAll. I have rewritten RunAsync3 as follows:
public static void RunAsync3(MethodAction doM)
{
Task[] t = new Task[4];
for(int i = 0; i < 4; i++)
{
t[i] = Task.Factory.StartNew((Action)(() => { doM(50 * i); }));
}
//Task.WaitAll(t); -> deadlock
Task.WaitAll(new Task [] { Task.WhenAll(t) });
if (OnProcCompletion != null) OnProcCompletion("RunSync method finished");
}
But this is still getting deadlocked...? I might be using the WhenAll incorrectly?
EDIT 2
Because everybody claiming that I was blocking the UI thread were right, I decided to try this another way: by running a new thread as my calling thread inside the UI thread (so that blocking now would occur on my thread instead of UI thread). This works, but is obviously not the best way to do this!
private void button4_Click(object sender, EventArgs e)
{
Thread t = new Thread(new ThreadStart(() =>
{
richTextBox1.Invoke((MethodConversion)(() => richTextBox1.Clear()));
sw.Reset();
sw.Start();
Sync.RunAsync3(calcSim);
}));
t.Start();
}
public static void RunAsync3(MethodAction doM)
{
Task[] t = new Task[4];
for(int i = 0; i < 4; i++)
{
t[i] = Task.Factory.StartNew((Action)(() => { doM(50 * i); }));
}
Task.WaitAll(t);
//Task.WaitAll(new Task [] { Task.WhenAll(t) });
if (OnProcCompletion != null) OnProcCompletion("RunSync method finished");
}

You're causing a deadlock.
The UI thread is waiting for 4 tasks to be completed.
On the other hand, those 4 tasks, running calcSim are trying to invoke code on the UI thread -> Deadlock.
You should be using Task.WhenAll() instead. That method will return a new task that will be marked as completed when all your for tasks have completed. If you await that task, your UI thread will be freed, and so calcSim will be able to invoke code on the UI thread, avoiding a deadlock.
Update
You're using it wrong. You're still using WaitAll, which is a blocking call. You should replace it with WhenAll.
await Task.WhenAll(t);
From the documentation:
Creates a task that will complete when all of the supplied tasks have
completed.
By calling await on the result, your UI thread will be free - until all 4 tasks complete. When that happens, your RunAsync3 method will resume.

Task.WaitAll blocks and waits for all task to complete and you are calling it on the UI thread.
All your task are trying to call richTextBox1.Invoke (in the UI thread) but your UI thread is blocked in Task.WaitAll. Deadlock.

Because it waits as your threads finish. They run exactly 3 seconds 300X10

Related

Application is not responding, when i tried to updated UI from another thread

Execution Flow:
From main thread I invoked the new thread(Parallel thread), which is doing a long running process.
Parallel thread is updating the main thread UI.
I made my main thread to wait until parallel thread is complete.
I need a synchronization between two thread.
I need to use the result of parallel thread in main thread so I blocked main thread until parallel process complete.
Here is my code which is having issue,
please give suggestion to resolve the issue.
private readonly AutoResetEvent _resetEvent = new AutoResetEvent(false);
private event EventHandler Workcompleted;
private void button1_Click(object sender, EventArgs e)
{
Workcompleted += Completed;
Thread thr = new Thread(UpdateUI);
thr.Start("");
_resetEvent.WaitOne();
// Logical operation dependent on parallel process final result
}
private void Completed(object sender, EventArgs args)
{
_resetEvent.Set();
}
private void UpdateUI(object txt)
{
for (int i = 0; i < 10; i++)
{
if (label1.InvokeRequired)
{
label1.Invoke(new ParameterizedThreadStart(UpdateUI), i.ToString());
}
else
{
label1.Text = (string)txt;
Thread.Sleep(100);
}
}
if (Workcompleted != null)
Workcompleted(this, new EventArgs());
}
I made my main thread to wait until parallel thread is complete.
And there you blocked yourself. Why did you start a new thread in the first place? To keep the UI responsive. And now your blocked it anyway. Do not block it. I don't know what you want to do while the thread is running, probably changing control states and resetting them when the thread is done, but what you don't want is blocking your UI thread. Stop that and find another way to achieve whatever you want to achieve.
It seems you are looking for a way to report progress in the UI during the course of the parallel operation and wait for the final result (synchronize) to do something with it.
This could easily be accomplished using Async/Await, without having to run manual threads, synchronization constructs or thread marshaling (for UI invocation) and most importantly without blocking the UI thread.
Here is an example of how to run a parallel operation, report progress back to the UI, update UI continuously and finally do something with the result when it is available.
private async void button1_Click(object sender, EventArgs e)
{
var progress = new Progress<int>(ShowProgressInUi);
var result = await Task.Run(() => DoParallelWorkAsync(progress));
// Do something with final result
label1.Text = result;
}
private void ShowProgressInUi(int progress)
{
label1.Text = string.Format("Progress: {0} % done...", progress);
}
private static async Task<string> DoParallelWorkAsync(IProgress<int> progress)
{
// This work is done in a separate thread.
// In this case a background thread (from the thread pool),
// but could be run on a foreground thread if the work is lengthy.
for (var i = 1; i <= 10; i++)
{
// Simulate workload
await Task.Delay(100);
progress.Report(i * 10);
}
return "All done";
}
public delegate void Action();
private void UpdateUI(object txt)
{
this.BeginInvoke((Action)(() =>
{
label2.Text = (string)txt;
}));
}
By using this code, we don't need to wait for another thread...

Waiting for an event-raising thread to cancel

I have a worker thread that reports progress by raising an event.
private volatile bool canRun;
public void Run()
{
for (int i = 0; i < count && canRun; i++)
{
// do stuff
OnProgressMade((float)i / (float)count);
}
OnWorkFinished();
}
public void Cancel()
{
canRun = false;
// wait for the thread to finish
}
In the Cancel method, I would like to wait for the thread to finish. Otherwise, someone might call Cancel and then immediately Dispose while the thread is still "doing stuff". If I used Join, there might be a deadlock - UI waits for the thread to cancel, thread waits for the UI to handle the ProgressMade event.
Is there a way to solve this nicely, or is it bad design from the beginning? My current solution relies on the UI waiting for the WorkFinished event before disposing the worker.
In the comments you hint that you might be able to use await (which is possible even on .NET 4.0). It could look like this:
MyWorker w;
CancellationTokenSource cts;
void OnStart(eventargs bla bla) {
cts = new ...();
w = new ...(cts.Token);
}
void OnCancel(eventargs bla bla) {
cts.Cancel();
await w.WaitForShutdown();
MsgBox("cancelled");
}
And we need to make MyWorker cooperate:
class MyWorker {
CancellationToken ct = <from ctor>;
TaskCompletionSource<object> shutdownCompletedTcs = new ...();
public void Run()
{
for (int i = 0; i < count && !ct.IsCancellationRequested; i++)
{
// do stuff
OnProgressMade((float)i / (float)count);
}
//OnWorkFinished(); //old
shutdownCompletedTcs.SetResult(null); //new, set "event"
}
public Task WaitForShutdown() {
return shutdownCompletedTcs.Task;
}
}
(Quickly slapped together.) Note, that all wait operations use await. They release the UI thread without interrupting your control flow.
Also note, that MyWorker is cooperatively cancellable. It does not know anything about the UI.

How do I properly wait for a task to complete an invocation using multiple threads?

The code below is a simplified example of a problem I am having. What happens upon the form loading - the For Loop will create a new task per iteration, then go as far as entering the 'if (pic.InvokeRequired)' section, but will return back to the For Loop and continue to iterate BEFORE any of the Tasks go through their respective invocations of method() after pic.BeginInvoke() is called.
What I am trying to achieve is for the invoking to complete it's second pass through method() and eventually changing the pic.BackColor to Color.Blue. I imagine this is possible, no? I've spent a couple hours searching around and could not find a satisfactory answer to this problem..
To run this code yourself, make a new WinForms Application Project (I'm using Visual Studio 2012) and add a PictureBox called 'pic'. Insert the code below.
Thank you for any and all help!
private void Form1_Load(object sender, EventArgs e)
{
for (int i = 0; i < 5; i++)
{
Task task = Task.Factory.StartNew(() => method());
task.Wait(); //Waits for task to complete before proceeding
}
}
public delegate void delegate_method();
private void method()
{
if (pic.InvokeRequired)
{
delegate_method dm = new delegate_method(() => method());
pic.BeginInvoke(dm); //If ran once (without the loop in Form1_Load) it would call 'method()' immediately from here.
}
else
{
pic.BackColor = Color.Blue;
}
}
I can appreciate the question because in some situations blocking may be preferable to full-on async (although it's more of a last resort measure).
The answer here depends on whether your async call (the actual meat of the work which happens in the background before you get to invoke an action on the UI thread - the part of the code which I'm assuming you chose to omit for the sake of simplicity) does any UI-bound work. If it does, you're out of luck and using Application.DoEvents() is your best bet.
If, however, it does not, and you have enough control over the async code, what you can do is instead of trying to invoke the UI from within your task, pass the Action describing the work back to your UI thread (as your Task's Result) and then handle its invocation there.
Note that I've simplified the implementation of Method() as it no longer gets called from non-UI threads.
WARNING: SIMPLIFIED CODE, NOT SUITABLE FOR PRODUCTION.
using System;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace PicInvoke
{
public partial class Form1 : Form
{
public Form1()
{
this.InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Stopwatch sw;
// Sequential processing.
sw = Stopwatch.StartNew();
this.DoWorkAndBlockSequential();
sw.Stop();
MessageBox.Show(string.Format("Sequential work complete. Time taken: {0:0.000}s.", (double)sw.ElapsedMilliseconds / 1000.0));
// Parallel processing.
sw = Stopwatch.StartNew();
this.DoWorkAndBlockParallel();
sw.Stop();
MessageBox.Show(string.Format("Parallel work complete. Time taken: {0:0.000}s.", (double)sw.ElapsedMilliseconds / 1000.0));
}
private void DoWorkAndBlockSequential()
{
for (int i = 0; i < 5; i++)
{
var task = this.DoWorkAsync();
// Block the UI thread until the task has completed.
var action = task.Result;
// Invoke the delegate.
action();
}
}
private void DoWorkAndBlockParallel()
{
var tasks = Enumerable
.Range(0, 5)
.Select(_ => this.DoWorkAsync())
.ToArray();
// Block UI thread until all tasks complete.
Task.WaitAll(tasks);
foreach (var task in tasks)
{
var action = task.Result;
// Invoke the delegate.
action();
}
}
private Task<Action> DoWorkAsync()
{
// Note: this CANNOT synchronously post messages
// to the UI thread as that will cause a deadlock.
return Task
// Simulate async work.
.Delay(TimeSpan.FromSeconds(1))
// Tell the UI thread what needs to be done via Task.Result.
// We are not performing the work here - merely telling the
// caller what needs to be done.
.ContinueWith(
_ => new Action(this.Method),
TaskContinuationOptions.ExecuteSynchronously);
}
private void Method()
{
pic.BackColor = Color.Blue;
}
}
}

Task Parallel with .net framework 4

I am studying parallelism and would like to know which way do you recommend for me to access other thead elements, for example, imagima I'll fill a combobox with some names, query the database I would do in parallel but I could not do a combobox.add (result) from within the task, which way do you recommend me?
a simple example to understand my question:
private void button1_Click (object sender, EventArgs e)
{
Task task = new Task (new Action (Count));
task.Start ();
}
void Count ()
{
for (int i = 0; i <99; i + +)
{
Thread.Sleep (1);
progressBar1.Value = i;
}
}
time to pass the value for the progressbar result in error
If you want to schedule a task that access UI controls, you need to pass the current synchronization context to the scheduler. If you do that the scheduler will make sure your task is executed on the correct thread. E.g.
var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
Task.Factory.StartNew(() => {
// code that access UI controls
}, uiScheduler);
For more info see http://msdn.microsoft.com/en-us/library/dd997402.aspx
You cannot access controls on another thread directly. You must invoke them first. Read this article: http://msdn.microsoft.com/en-us/library/ms171728.aspx
This is about what is would look like if you took the article and translated it for your own use: (NOT TESTED)
delegate void SetProgressBarCallback();
private void SetProgressBar()
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.progressBar1.InvokeRequired)
{
SetProgressBarCallback d = new SettProgressBarCallback(SetProgressBar);
this.Invoke(d);
}
else
{
for(int i=0; i<99; i++)
{
Thread.Sleep(1);
progressBar1.Value = i;
}
}
}
Just a quick note... the UI in WinForms can only be updated from the UI thread. Perhaps you should consider using Control.Invoke to update your progressBar1.
Ryan's answer was correct but he put the sleep inside the invoke, that caused the program to hang. Here is a example that uses the same thing he did but it does not put the sleep in the invoke.
private void button1_Click (object sender, EventArgs e)
{
Task task = new Task (new Action (Count));
task.Start ();
}
void Count ()
{
for (int i = 0; i <99; i + +)
{
Thread.Sleep (1);
if(progressBar1.InvokeRequired)
{
int j = i; //This is required to capture the variable, if you do not do this
// the delegate may not have the correct value when you run it;
progressBar1.Invoke(new Action(() => progressBar1.Value = j));
}
else
{
progressBar1.Value = i;
}
}
}
You must do the int j = i to do variable capture, otherwise it could bring up the wrong value for i inside the loop.

Implementing a thread queue/wait, how?

I have a timer calling a function every 15 minutes, this function counts the amount of lines in my DGV and starts a thread for each lines (of yet another function), said thread parse a web page which can take anywhere from 1 second to 10 second to finish.
Whilst it does work fine as it is with 1-6 rows, anymore will cause the requests to time-out.
I want it to wait for the newly created thread to finish processing before getting back in the loop to create another thread without locking the main UI
for (int x = 0; x <= dataGridFollow.Rows.Count - 1; x++)
{
string getID = dataGridFollow.Rows[x].Cells["ID"].Value.ToString();
int ID = int.Parse(getID);
Thread t = new Thread(new ParameterizedThreadStart(UpdateLo));
t.Start(ID);
// <- Wait for thread to finish here before getting back in the for loop
}
I have googled a lot in the past 24 hours, read a lot about this specific issue and its implementations (Thread.Join, ThreadPools, Queuing, and even SmartThreadPool).
It's likely that I've read the correct answer somewhere but I'm not at ease enough with C# to decypher those Threading tools
Thanks for your time
to avoid the UI freeze the framework provide a class expressly for these purposes: have a look at the BackgroundWorker class (executes an operation on a separate thread), here's some infos : http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx
http://msdn.microsoft.com/en-us/magazine/cc300429.aspx
Btw looks if I understand correctly you don't want to parallelize any operation so just wait for the method parsing the page to be completed. Basically for each (foreach look) row of your grid you get the id and call the method. If you want to go parallel just reuse the same foreach loop and add make it Parallel
http://msdn.microsoft.com/en-us/library/dd460720.aspx
What you want is to set off a few workers that do some task.
When one finishes you can start a new one off.
I'm sure there is a better way using thread pools or whatever.. but I was bored so i came up with this.
using System;
using System.Collections.Generic;
using System.Linq;
using System.ComponentModel;
using System.Threading;
namespace WorkerTest
{
class Program
{
static void Main(string[] args)
{
WorkerGroup workerGroup = new WorkerGroup();
Console.WriteLine("Starting...");
for (int i = 0; i < 100; i++)
{
var work = new Action(() =>
{
Thread.Sleep(1000); //somework
});
workerGroup.AddWork(work);
}
while (workerGroup.WorkCount > 0)
{
Console.WriteLine(workerGroup.WorkCount);
Thread.Sleep(1000);
}
Console.WriteLine("Fin");
Console.ReadLine();
}
}
public class WorkerGroup
{
private List<Worker> workers;
private Queue<Action> workToDo;
private object Lock = new object();
public int WorkCount { get { return workToDo.Count; } }
public WorkerGroup()
{
workers = new List<Worker>();
workers.Add(new Worker());
workers.Add(new Worker());
foreach (var w in workers)
{
w.WorkCompleted += (OnWorkCompleted);
}
workToDo = new Queue<Action>();
}
private void OnWorkCompleted(object sender, EventArgs e)
{
FindWork();
}
public void AddWork(Action work)
{
workToDo.Enqueue(work);
FindWork();
}
private void FindWork()
{
lock (Lock)
{
if (workToDo.Count > 0)
{
var availableWorker = workers.FirstOrDefault(x => !x.IsBusy);
if (availableWorker != null)
{
var work = workToDo.Dequeue();
availableWorker.StartWork(work);
}
}
}
}
}
public class Worker
{
private BackgroundWorker worker;
private Action work;
public bool IsBusy { get { return worker.IsBusy; } }
public event EventHandler WorkCompleted;
public Worker()
{
worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler(OnWorkerDoWork);
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(OnWorkerRunWorkerCompleted);
}
private void OnWorkerRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (WorkCompleted != null)
{
WorkCompleted(this, EventArgs.Empty);
}
}
public void StartWork(Action work)
{
if (!IsBusy)
{
this.work = work;
worker.RunWorkerAsync();
}
else
{
throw new InvalidOperationException("Worker is busy");
}
}
private void OnWorkerDoWork(object sender, DoWorkEventArgs e)
{
work.Invoke();
work = null;
}
}
}
This would be just a starting point.
You could start it off with a list of Actions and then have a completed event for when that group of actions is finished.
then at least you can use a ManualResetEvent to wait for the completed event.. or whatever logic you want really.
Call a method directly or do a while loop (with sleep calls) to check the status of the thread.
There are also async events but the would call another method, and you want to continue from the same point.
I have no idea why the requests would timeout. That sounds like a different issue. However, I can make a few suggestions regarding your current approach.
Avoid creating threads in loops with nondeterministic bounds. There is a lot of overhead in creating threads. If the number of operations is not known before hand then use the ThreadPool or the Task Parallel Library instead.
You are not going to get the behavior you want by blocking the UI thread with Thread.Join. The cause the UI to become unresponsive and it will effectively serialize the operations and cancel out any advantage you were hoping to gain with threads.
If you really want to limit the number of concurrent operations then a better solution is to create a separate dedicated thread for kicking off the operations. This thread will spin around a loop indefinitely waiting for items to appear in a queue and when they do it will dequeue them and use that information to kick off an operation asynchronously (again using the ThreadPool or TPL). The dequeueing thread can contain the logic for limiting the number of concurrent operations. Search for information regarding the producer-consumer pattern to get a better understand of how you can implement this.
There is a bit of a learning curve, but who said threading was easy right?
If I understand correctly, what you're currently doing is looping through a list of IDs in the UI thread, starting a new thread to handle each one. The blocking issue you're seeing then could well be that it's taking too many resources to create unique threads. So, personally (without knowing more) would redesign the process like so:
//Somewhere in the UI Thread
Thread worker = new Thread(new ParameterizedThreadStart(UpdateLoWorker));
worker.Start(dataGridFollow.Rows);
//worker thread
private void UpdateLoWorker(DataRowCollection rows)
{
foreach(DataRow r in rows){
string getID = r.Cells["ID"].Value.ToString();
int ID = int.Parse(getID);
UpdateLo(ID);
}
}
Here you'd have a single non-blocking worker which sequentially handles each ID.
Consider using Asynchronous CTP. It's an asynch pattern Microsoft recently released for download. It should simplify asynch programming tremendouesly. The link is http://msdn.microsoft.com/en-us/vstudio/async.aspx. (Read the whitepaper first)
Your code would look something like the following. (I've not verified my syntax yet, sorry).
private async Task DoTheWork()
{
for(int x = 0; x <= dataGridFollow.Rows.Count - 1; x++)
{
string getID = dataGridFollow.Rows[x].Cells["ID"].Value.ToString();
int ID = int.Parse(getID);
task t = new Task(new Action<object>(UpdateLo), ID);
t.Start();
await t;
}
}
This method returns a Task that can be checked periodically for completion. This follows the pattern of "fire and forget" meaning you just call it and presumably, you don't care when it completes (as long as it does complete before 15 minutes).
EDIT
I corrected the syntax above, you would need to change UpdateLo to take an object instead of an Int.
For a simple background thread runner that will run one thread from a queue at a time you can do something like this:
private List<Thread> mThreads = new List<Thread>();
public static void Main()
{
Thread t = new Thread(ThreadMonitor);
t.IsBackground = true;
t.Start();
}
private static void ThreadMonitor()
{
while (true)
{
foreach (Thread t in mThreads.ToArray())
{
// Runs one thread in the queue and waits for it to finish
t.Start();
mThreads.Remove(t);
t.Join();
}
Thread.Sleep(2000); // Wait before checking for new threads
}
}
// Called from the UI or elsewhere to create any number of new threads to run
public static void DoStuff()
{
Thread t = new Thread(DoCorestuff);
t.IsBackground = true;
mActiveThreads.Add(t);
}
public static void DoStuffCore()
{
// Your code here
}

Categories

Resources