I have two tasks Job1 and Job2 and below is the code. First time I ran Job1 and Job2 in a sequence and got the stopwatch output as 844 milliseconds. Second time I commented sequential jobs and called parallel task processing and got the stopwatch result as 11352 milliseconds. My assumption/expectation was I should get the output as 422 (because 844/2) or somewhere near to it. But the result is totally opposite. I need to wait both the jobs to be completed and hence I put t1.Wait() and t2.Wait(); Please help me to process these two jobs in half of sequential processing. Please find my code below:
public ActionResult Index()
{
Stopwatch s = new Stopwatch();
s.Start();
//Execute 2 jobs in a sequence
Job1();
Job2();
//Execute 2 jobs in parallel
//var t1 = Task.Run(() => { Job1(); });
//var t2 = Task.Run(() => { Job2(); });
//t1.Wait();
//t2.Wait();
s.Stop();
Debug.WriteLine("ElapsedMilliseconds: " + s.ElapsedMilliseconds);
return View();
}
private void Job1()
{
for (int i = 0; i < 1000; i++)
{
Debug.WriteLine(i);
}
}
private void Job2()
{
for (int i = 2000; i < 3000; i++)
{
Debug.WriteLine(i);
}
}
Essentially your 2nd example is slower due to the overhead of Debug.WriteLine during concurrency.
You'd notice a big difference if you remove Debug.WriteLine (which calls OutputDebugString under the hood).
MSDN states:
Applications should send very minimal debug output and provide a way for the user to enable or disable its use. To provide more detailed tracing, see Event Tracing.
As Eran states here:
"if several threads call OutputDebugString concurrently, they will be synchronized".
There's no concurrency in your first example so that could be a reason why its faster.
Also you might want to consider moving to a single wait.
Change your code from this:
//Execute 2 jobs in parallel
var t1 = Task.Run(() => { Job1(); });
var t2 = Task.Run(() => { Job2(); });
t1.Wait();
t2.Wait();
...to this:
//Execute 2 jobs in parallel
var tasks = new List<Task>();
tasks.Add(Task.Run(() => { Job1(); }));
tasks.Add(Task.Run(() => { Job2(); }));
Task.WaitAll(tasks.ToArray());
To understand why Tasks have nothing to do with performance but more with responsiveness you should read up on
Context switching: https://en.wikipedia.org/wiki/Context_switch
The processor uses lots of cycles to switch to another thread
Mutexes: https://en.wikipedia.org/wiki/Mutual_exclusion
Every time you call Debug.WriteLine the Task waits until Debug.WriteLine in the other Task is done and performs a context switch.
Related
Consider the following program, which uses TPL Dataflow. Hence, ActionBlock comes from the Dataflow library.
internal static class Program
{
public static async Task Main(string[] args)
{
var actionBlock = new ActionBlock<int>(async i =>
{
Console.WriteLine($"Started with {i}");
await DoSomethingAsync(i);
Console.WriteLine($"Done with {i}");
});
for (int i = 0; i < 5; i++)
{
actionBlock.Post(i);
}
actionBlock.Complete();
await actionBlock.Completion;
}
private static async Task DoSomethingAsync(int i)
{
await Task.Delay(1000);
}
}
The output of this program is:
Started with 0
Done with 0
Started with 1
Done with 1
Started with 2
Done with 2
Started with 3
Done with 3
Started with 4
Done with 4
Reason is that the ActionBlock only starts processing the next task when the previous asynynchronous task was finished.
How can I force it to start processing the next task, even though the previous wasn't fully finished. MaxDegreeOfParallelism isn't an option, as that can mess up the order.
So I'd like the output to be:
Started with 0
Started with 1
Started with 2
Started with 3
Started with 4
Done with 0
Done with 1
Done with 2
Done with 3
Done with 4
I could get rid of the async/await and replace it with ContinueWith. But that has two disadvantages:
The ActionBlock think it's done with the message immediately. An optional call to Complete() would result in the pipeline being completed directly, instead of after the asynchronous action to be completed.
I'd like to add a BoundedCapacity to limit the amount of messages currently still waiting to be fully finished. But because of 1. this BoundedCapacity has no effect.
In situations like this I would try to remove the requirement that things get processed in order, so that you can process in parallel, and then report sequentially.
//The transform block can process everything in parallel,
//but by default the inputs and outputs remain ordered
var processStuff = new TransformBlock<int, string>(async i =>
{
Console.WriteLine($"Started with {i}");
await DoSomethingAsync(i);
return $"Done with {i}";
}, new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 5 });
//This action block is your reporting block that uses the results from
//the transform block, and it will be executed in order.
var useStuff = new ActionBlock<string>(result =>
{
Console.WriteLine(result);
});
//when linking make sure to propagate completion.
processStuff.LinkTo(useStuff, new DataflowLinkOptions { PropagateCompletion = true });
for (int i = 0; i < 5; i++)
{
Console.WriteLine("Posting {0}", i);
processStuff.Post(i);
}
//mark the top of your pipeline as complete, and that will propagate
//to the end.
processStuff.Complete();
//wait on your last block to finish processing everything.
await useStuff.Completion;
output from this code produced the following as an example. Notice that the "started with" statements are not necessarily even in the order of the postings.
Posting 0
Posting 1
Posting 2
Posting 3
Posting 4
Started with 1
Started with 0
Started with 2
Started with 4
Started with 3
Done with 0
Done with 1
Done with 2
Done with 3
Done with 4
I did, in the meantime, find a solution/workaround, by using two blocks, and passing the asynchronous Task from the first block to the next block, where it is waited for synchronously using .Wait().
So, like this:
using System.Reactive.Linq;
using System.Threading.Tasks.Dataflow;
internal static class Program
{
public static async Task Main(string[] args)
{
var transformBlock = new TransformBlock<int, Task<int>>(async i =>
{
Console.WriteLine($"Started with {i}");
await DoSomethingAsync(i);
return i;
});
var actionBlock = new ActionBlock<Task<int>>(task =>
{
task.Wait();
Console.WriteLine($"Done with {task.Result}");
});
transformBlock.LinkTo(actionBlock, new DataflowLinkOptions { PropagateCompletion = true });
for (int i = 0; i < 5; i++)
{
transformBlock.Post(i);
}
transformBlock.Complete();
await actionBlock.Completion;
}
private static Task DoSomethingAsync(int i)
{
return Task.Delay(1000);
}
}}
}
This way the first block just considers itself done with a message almost instantly and is able to handle, in order, the next message which calls DoSomethingAsync directly, without waiting for the response of the previous call.
I am trying to get 2 tasks to fire at the same time at a specific point in time, then do it all over again. For example, below is a task that waits 1 minute and a second task that waits 5 minutes. The 1 minute task should fire 5 times in 5 minutes and the 5 minute task 1 time, the 1 minute task should fire 10 times in 10 minutes and the 5 minute task 2 times, on and on and on. However, I need the 1 minute task to fire at the same time as the 5 minute.
I was able to do this with System.Timers but that did not play well with the multithreading that I eventually needed. System.Thread did not have anything equivalent to System.Timers AutoReset unless I'm missing something.
What I have below is both delay timers start at the same time BUT t1 only triggers 1 time and not 5. Essentially it needs to keep going until the program is stopped not just X times.
int i = 0;
while (i < 1)
{
Task t1 = Task.Run(async delegate
{
await Task.Delay(TimeSpan.FromMinutes(1));
TaskWorkers.OneMinuteTasks();
});
//t1.Wait();
Task t2 = Task.Run(async delegate
{
await Task.Delay(TimeSpan.FromMinutes(5));
TaskWorkers.FiveMinuteTasks();
});
t2.Wait();
}
Update
I first read Johns comment below about just adding an inner loop to the Task. Below works as I was wanting. Simple fix. I know I did say I would want this to run for as long as the program runs but I was able to calculate out the max number of loops I would actually need. x < 10 is just a number I choose.
Task t1 = Task.Run(async delegate
{
for(int x = 0; x < 10; x++)
{
await Task.Delay(TimeSpan.FromMinutes(1));
TaskWorkers.OneMinuteTasks();
}
});
Task t2 = Task.Run(async delegate
{
for (int x = 0; x < 10; x++)
{
await Task.Delay(TimeSpan.FromMinutes(5));
TaskWorkers.FiveMinuteTasks();
}
});
As far as I can tell no gross usage of CPU or memory.
You could have a single loop that periodically fires the tasks in a coordinated fashion:
async Task LoopAsync(CancellationToken token)
{
while (true)
{
Task a = DoAsync_A(); // Every 5 minutes
for (int i = 0; i < 5; i++)
{
var delayTask = Task.Delay(TimeSpan.FromMinutes(1), token);
Task b = DoAsync_B(); // Every 1 minute
await Task.WhenAll(b, delayTask);
if (a.IsCompleted) await a;
}
await a;
}
}
This implementation awaits both the B task and the Task.Delay task to complete before starting a new 1-minute loop, so if the B task is extremely long-running, the schedule will slip. This is probably a desirable behavior, unless you are OK with the possibility of overlapping tasks.
In case of an exception in either the A or B task, the loop will report failure at the one minute checkpoints. This is not ideal, but making the loop perfectly responsive on errors would make the code quite complicated.
Update: Here is an advanced version that is more responsive in case of an exception. It uses a linked CancellationTokenSource, that is automatically canceled when any of the two tasks fails, which then results to the immediate cancellation of the delay task.
async Task LoopAsync(CancellationToken token)
{
using (var linked = CancellationTokenSource.CreateLinkedTokenSource(token))
{
while (true)
{
Task a = DoAsync_A(); // Every 5 minutes
await WithCompletionAsync(a, async () =>
{
OnErrorCancel(a, linked);
for (int i = 0; i < 5; i++)
{
var delayTask = Task.Delay(TimeSpan.FromMinutes(1),
linked.Token);
await WithCompletionAsync(delayTask, async () =>
{
Task b = DoAsync_B(); // Every 1 minute
OnErrorCancel(b, linked);
await b;
if (a.IsCompleted) await a;
});
}
});
}
}
}
async void OnErrorCancel(Task task, CancellationTokenSource cts)
{
try
{
await task.ConfigureAwait(false);
}
catch
{
cts.Cancel();
//try { cts.Cancel(); } catch { } // Safer alternative
}
}
async Task WithCompletionAsync(Task task, Func<Task> body)
{
try
{
await body().ConfigureAwait(false);
}
catch (OperationCanceledException)
{
await task.ConfigureAwait(false);
throw; // The task isn't faulted. Propagate the exception of the body.
}
catch
{
try
{
await task.ConfigureAwait(false);
}
catch { } // Suppress the task's exception
throw; // Propagate the exception of the body
}
await task.ConfigureAwait(false);
}
The logic of this version is significantly more perplexed than the initial simple version (which makes it more error prone). The introduction of the CancellationTokenSource creates the need for disposing it, which in turn makes mandatory to ensure that all tasks will be completed on every exit point of the asynchronous method. This is the reason for using the WithCompletionAsync method to enclose all code that follows every task inside the LoopAsync method.
I think timers or something like Vasily's suggestion would be the way to go, as these solutions are designed to handle recurring tasks more than just using threads. However, you could do this using threads, saying something like:
void TriggerTimers()
{
new Thread(() =>
{
while (true)
{
new Thread(()=> TaskA()).Start();
Thread.Sleep(60 * 1000); //start taskA every minute
}
}).Start();
new Thread(() =>
{
while (true)
{
new Thread(() => TaskB()).Start();
Thread.Sleep(5 * 60 * 1000); //start taskB every five minutes
}
}).Start();
}
void TaskA() { }
void TaskB() { }
Note that this solution will drift out my a small amount if used over a very long period of time, although this shouldn't be significant unless you're dealing with very delicate margins, or a very overloaded computer. Also, this solution doesn't have contingency for the description John mentioned - it's fairly lightweight, but also quite understandable
I am using Async await with Task.Factory method.
public async Task<JobDto> ProcessJob(JobDto jobTask)
{
try
{
var T = Task.Factory.StartNew(() =>
{
JobWorker jobWorker = new JobWorker();
jobWorker.Execute(jobTask);
});
await T;
}
This method I am calling inside a loop like this
for(int i=0; i < jobList.Count(); i++)
{
tasks[i] = ProcessJob(jobList[i]);
}
What I notice is that new tasks opens up inside Process explorer and they also start working (based on log file). however out of 10 sometimes 8 or sometimes 7 finishes. Rest of them just never come back.
why would that be happening ?
Are they timing out ? Where can I set timeout for my tasks ?
UPDATE
Basically above, I would like each Task to start running as soon as they are called and wait for the response on AWAIT T keyword. I am assuming here that once they finish each of them will come back at Await T and do the next action. I am alraedy seeing this result for 7 out of 10 tasks but 3 of them are not coming back.
Thanks
It is hard to say what the issues is without the rest if the code, but you code can be simplified by making ProcessJob synchronous and then calling Task.Run with it.
public JobDto ProcessJob(JobDto jobTask)
{
JobWorker jobWorker = new JobWorker();
return jobWorker.Execute(jobTask);
}
Start tasks and wait for all tasks to finish. Prefer using Task.Run rather than Task.Factory.StartNew as it provides more favourable defaults for pushing work to the background. See here.
for(int i=0; i < jobList.Count(); i++)
{
tasks[i] = Task.Run(() => ProcessJob(jobList[i]));
}
try
{
await Task.WhenAll(tasks);
}
catch(Exception ex)
{
// handle exception
}
First, let's make a reproducible version of your code. This is NOT the best way to achieve what you are doing, but to show you what is happening in your code!
I'll keep the code almost same as your code, except I'll use simple int rather than your JobDto and on completion of the job Execute() I'll write in a file that we can verify later. Here's the code
public class SomeMainClass
{
public void StartProcessing()
{
var jobList = Enumerable.Range(1, 10).ToArray();
var tasks = new Task[10];
//[1] start 10 jobs, one-by-one
for (int i = 0; i < jobList.Count(); i++)
{
tasks[i] = ProcessJob(jobList[i]);
}
//[4] here we have 10 awaitable Task in tasks
//[5] do all other unrelated operations
Thread.Sleep(1500); //assume it works for 1.5 sec
// Task.WaitAll(tasks); //[6] wait for tasks to complete
// The PROCESS IS COMPLETE here
}
public async Task ProcessJob(int jobTask)
{
try
{
//[2] start job in a ThreadPool, Background thread
var T = Task.Factory.StartNew(() =>
{
JobWorker jobWorker = new JobWorker();
jobWorker.Execute(jobTask);
});
//[3] await here will keep context of calling thread
await T; //... and release the calling thread
}
catch (Exception) { /*handle*/ }
}
}
public class JobWorker
{
static object locker = new object();
const string _file = #"C:\YourDirectory\out.txt";
public void Execute(int jobTask) //on complete, writes in file
{
Thread.Sleep(500); //let's assume does something for 0.5 sec
lock(locker)
{
File.AppendAllText(_file,
Environment.NewLine + "Writing the value-" + jobTask);
}
}
}
After running just the StartProcessing(), this is what I get in the file
Writing the value-4
Writing the value-2
Writing the value-3
Writing the value-1
Writing the value-6
Writing the value-7
Writing the value-8
Writing the value-5
So, 8/10 jobs has completed. Obviously, every time you run this, the number and order might change. But, the point is, all the jobs did not complete!
Now, if I un-comment the step [6] Task.WaitAll(tasks);, this is what I get in my file
Writing the value-2
Writing the value-3
Writing the value-4
Writing the value-1
Writing the value-5
Writing the value-7
Writing the value-8
Writing the value-6
Writing the value-9
Writing the value-10
So, all my jobs completed here!
Why the code is behaving like this, is already explained in the code-comments. The main thing to note is, your tasks run in ThreadPool based Background threads. So, if you do not wait for them, they will be killed when the MAIN process ends and the main thread exits!!
If you still don't want to await the tasks there, you can return the list of tasks from this first method and await the tasks at the very end of the process, something like this
public Task[] StartProcessing()
{
...
for (int i = 0; i < jobList.Count(); i++)
{
tasks[i] = ProcessJob(jobList[i]);
}
...
return tasks;
}
//in the MAIN METHOD of your application/process
var tasks = new SomeMainClass().StartProcessing();
// do all other stuffs here, and just at the end of process
Task.WaitAll(tasks);
Hope this clears all confusion.
It's possible your code is swallowing exceptions. I would add a ContineWith call to the end of the part of the code that starts the new task. Something like this untested code:
var T = Task.Factory.StartNew(() =>
{
JobWorker jobWorker = new JobWorker();
jobWorker.Execute(jobTask);
}).ContinueWith(tsk =>
{
var flattenedException = tsk.Exception.Flatten();
Console.Log("Exception! " + flattenedException);
return true;
});
},TaskContinuationOptions.OnlyOnFaulted); //Only call if task is faulted
Another possibility is that something in one of the tasks is timing out (like you mentioned) or deadlocking. To track down whether a timeout (or maybe deadlock) is the root cause, you could add some timeout logic (as described in this SO answer):
int timeout = 1000; //set to something much greater than the time it should take your task to complete (at least for testing)
var task = TheMethodWhichWrapsYourAsyncLogic(cancellationToken);
if (await Task.WhenAny(task, Task.Delay(timeout, cancellationToken)) == task)
{
// Task completed within timeout.
// Consider that the task may have faulted or been canceled.
// We re-await the task so that any exceptions/cancellation is rethrown.
await task;
}
else
{
// timeout/cancellation logic
}
Check out the documentation on exception handling in the TPL on MSDN.
I have sample code to compare processing time for Parallel approach and Task approach. The goal of this experiment is understanding of how do they work.
So my questions are:
Why Parallel worked faster then Task?
Do my results mean that I should use Parallel instead of Task?
Where should I use Task and where Parallel?
What benefits of using Task in comparison to Parallel?
Does Task is just a wrap for ThreadPool.QueueUserWorkItem method?
public Task SomeLongOperation()
{
return Task.Delay(3000);
}
static void Main(string[] args)
{
Program p = new Program();
List<Task> tasks = new List<Task>();
tasks.Add(Task.Factory.StartNew(() => p.SomeLongOperation()));
tasks.Add(Task.Factory.StartNew(() => p.SomeLongOperation()));
var arr = tasks.ToArray();
Stopwatch sw = Stopwatch.StartNew();
Task.WaitAll(arr);
Console.WriteLine("Task wait all results: " + sw.Elapsed);
sw.Stop();
sw = Stopwatch.StartNew();
Parallel.Invoke(() => p.SomeLongOperation(), () => p.SomeLongOperation());
Console.WriteLine("Parallel invoke results: " + sw.Elapsed);
sw.Stop();
Console.ReadKey();
}
Here are my processing results:
EDIT:
Changed code to look like this:
Program p = new Program();
Task[] tasks = new Task[2];
Stopwatch sw = Stopwatch.StartNew();
tasks[0] = Task.Factory.StartNew(() => p.SomeLongOperation());
tasks[1] = Task.Factory.StartNew(() => p.SomeLongOperation());
Task.WaitAll(tasks);
Console.WriteLine("Task wait all results: " + sw.Elapsed);
sw.Stop();
sw = Stopwatch.StartNew();
Parallel.Invoke(() => p.SomeLongOperation(), () => p.SomeLongOperation());
Console.WriteLine("Parallel invoke results: " + sw.Elapsed);
sw.Stop();
My new results:
EDIT 2:
When I replaced code with Parallel.Invoke to be first and Task.WaitAll to be second the situation has been changed cardinally. Now Parallel is slower. It makes me think of incorrectness of my estimates. I changed code to look like this:
Program p = new Program();
Task[] tasks = new Task[2];
Stopwatch sw = null;
for (int i = 0; i < 10; i++)
{
sw = Stopwatch.StartNew();
Parallel.Invoke(() => p.SomeLongOperation(), () => p.SomeLongOperation());
string res = sw.Elapsed.ToString();
Console.WriteLine("Parallel invoke results: " + res);
sw.Stop();
}
for (int i = 0; i < 10; i++)
{
sw = Stopwatch.StartNew();
tasks[0] = Task.Factory.StartNew(() => p.SomeLongOperation());
tasks[1] = Task.Factory.StartNew(() => p.SomeLongOperation());
Task.WaitAll(tasks);
string res2 = sw.Elapsed.ToString();
Console.WriteLine("Task wait all results: " + res2);
sw.Stop();
}
And here are my new results:
Now I can suggest that this experiment is much more clear. The results are almost the same. Sometimes Parallel and sometimes Task is faster. Now my questions are:
1. Where should I use Task and where Parallel?
2. What benefits of using Task in comparison to Parallel?
3. Does Task is just a wrap for ThreadPool.QueueUserWorkItem method?
Any helpful info that can clarify those questions are welcome.
EDIT as of this article from MSDN:
Both Parallel and Task are wrappers for ThreadPool. Parallel invoke also awaits until all tasks will be finished.
Related to your questions:
Using Task, Parallel or ThreadPool depends on the granularity of control you need to have on the execution of your parallel tasks. I'm personally got used to Task.Factory.StartNew(), but that's a personal opinion. The same relates to ThreadPool.QueueUserWorkItem()
Additional Information: The first call to Parallel.Invoke() and Task.Factory.StartNew() might be slower due to internal initialization.
If you start nongeneric Tasks(i.e. "void Tasks without a return value") and immediately Wait for them, use Parallel.Invoke instead. Your intent is immediately clear to the reader.
Use Tasks if:
you do not Wait immediately
you need return values
you need to give parameters to the methods called
you require TaskCreationOptions functionality
you require CancellationToken or TaskScheduler functionality and don't want to use ParallelOptions
basically, if you want more options or control
Yes, you can get around some of these, e.g. Parallel.Invoke(() => p.OpWithToken(CancellationToken) but that obfuscates your intent. Parallel.Invoke is for doing a bunch of work using as much CPU power as possible. It gets done, it doesn't deadlock, and you know this in advance.
Your testing is horrid though. The red flag would be that your long action is to wait 3000 milliseconds, yet your tests take less than a tenth of a millisecond.
Task.Factory.StartNew(() => p.SomeLongOperation());
StartNew takes an Action, and executes this in a new main Task. The action () => SomeLongOperation() creates a subtask Task. After this subtask is created (not completed), the call to SomeLongOperation() returns, and the Action is done. So the main Task is already completed after a tenth millisecond, while the two subtasks you have no reference to are still running in the background. The Parallel path also creates two subtasks, which it doesn't track at all, and returns.
The correct way would be tasks[0] = p.SomeLongOperation();, which assigns a running task to the array. Then WaitAll checks for the finishing of this task.
Say I have 10N items(I need to fetch them via http protocol), in the code N Tasks are started to get data, each task takes 10 items in sequence. I put the items in a ConcurrentQueue<Item>. After that, the items are processed in a thread-unsafe method one by one.
async Task<Item> GetItemAsync()
{
//fetch one item from the internet
}
async Task DoWork()
{
var tasks = new List<Task>();
var items = new ConcurrentQueue<Item>();
var handles = new List<ManualResetEvent>();
for i 1 -> N
{
var handle = new ManualResetEvent(false);
handles.Add(handle);
tasks.Add(Task.Factory.StartNew(async delegate
{
for j 1 -> 10
{
var item = await GetItemAsync();
items.Enqueue(item);
}
handle.Set();
});
}
//begin to process the items when any handle is set
WaitHandle.WaitAny(handles);
while(true)
{
if (all handles are set && items collection is empty) //***
break;
//in another word: all tasks are really completed
while(items.TryDequeue(out item))
{
AThreadUnsafeMethod(item); //process items one by one
}
}
}
I don't know what if condition can be placed in the statement marked ***. I can't use Task.IsCompleted property here, because I use await in the task, so the task is completed very soon. And a bool[] that indicates whether the task is executed to the end looks really ugly, because I think ManualResetEvent can do the same work. Can anyone give me a suggestion?
Well, you could build this yourself, but I think it's tons easier with TPL Dataflow.
Something like:
static async Task DoWork()
{
// By default, ActionBlock uses MaxDegreeOfParallelism == 1,
// so AThreadUnsafeMethod is not called in parallel.
var block = new ActionBlock<Item>(AThreadUnsafeMethod);
// Start off N tasks, each asynchronously acquiring 10 items.
// Each item is sent to the block as it is received.
var tasks = Enumerable.Range(0, N).Select(Task.Run(
async () =>
{
for (int i = 0; i != 10; ++i)
block.Post(await GetItemAsync());
})).ToArray();
// Complete the block when all tasks have completed.
Task.WhenAll(tasks).ContinueWith(_ => { block.Complete(); });
// Wait for the block to complete.
await block.Completion;
}
You can do a WaitOne with a timeout of zero to check the state. Something like this should work:
if (handles.All(handle => handle.WaitOne(TimeSpan.Zero)) && !items.Any())
break;
http://msdn.microsoft.com/en-us/library/cc190477.aspx
Thanks all. At last I found CountDownEvent is very suitable for this scenario. The general implementation looks like this:(for others' information)
for i 1 -> N
{
//start N tasks
//invoke CountDownEvent.Signal() at the end of each task
}
//see if CountDownEvent.IsSet here