Multi await Task.Run handle - c#

I have write 2 normal function (long task function) and want to call the function async. So the below code is here
Public async void AsyncTask()
{
Form MainForm = await Task.Run(() => CreateAppForm());
DataTable[] MasterTables = await Task.Run(() => CreateTables());
// How to write code for below task run complete and go to next step ?
}
public DataTable[] CreateTables()
{
// Below code is create datatable from SQL DataTable
DataTable [] MasterTables;
return MasterTables;
}
public Form CreateAppForm ()
{
Form masterForm= new Form();
// write some long task code
return masterForm;
}
I want CreateTables and CreateForm run at same time (Parallel) and the main Thread need to wait the above function run complete. Can I know how to handle it ?
Thank you .

Putting aside the issue of whether this will actually achieve what you want...
If you want to start a Task, you just create it. When you want the result of the Task, you await it. So split up the lines where you start the Task and when you await it:
public async Task AsyncTask()
{
//start the Tasks so they run concurrently
var mainFormTask = Task.Run(() => CreateAppForm());
var createTableTask = Task.Run(() => CreateTables());
//await the Tasks and get the results
Form MainForm = await mainFormTask;
DataTable[] MasterTables = await createTableTask;
}
But again, I'm not entirely sure if that's really a great idea (or will do anything meaningful) in this specific scenario.

Use Thread.WaitAll(); See Thread.WaitAll Method
var tasks = new[]
{
Task.Factory.StartNew(() => DoSomething1()),
Task.Factory.StartNew(() => DoSomething2()),
Task.Factory.StartNew(() => DoSomething3())
};
Task.WaitAll(tasks);
// Code below this line will execute after all asyncs have completed
var x = "test";
EDIT: Now storing the return of the async method to variables;
string return1 = string.Empty;
string return2 = string.Empty;
var tasks = new[]
{
Task.Factory.StartNew(() => return1 = "First return"),
Task.Factory.StartNew(() => return2 = "Second return"),
};
Task.WaitAll(tasks);
Console.WriteLine(return1); // First return
Console.WriteLine(return2); // Second return

Related

C# wait DLL async method to finish

I have a DLL which has public Task<> method which returns return Task.Factory.StartNew(() => ...). I am calling it within a program and I want the program to wait for the execution of the task to finish before it continues doing other things. I've added Thread.Sleep(6000) to the DLL to simulate longer execution.
When I'm calling it like this
var invokedTask = myMethod.Invoke(Activator.CreateInstance(myClass), myParams);
It just continues with execution (as expected). But then I tried this:
var invokedTask = Task.Factory.StartNew(() => myMethod.Invoke(Activator.CreateInstance(myClass), myParams));
invokedTask.Wait();
And it doesn't work. How can I make it wait from outside of DLL?
Just Wait for the task that is being returned - don't spin up another Task just to call the original method:
var invokedTask = (Task)myMethod.Invoke(Activator.CreateInstance(myClass), myParams);
invokedTask.Wait();
I think the calling method must have the async keyword in the definition:
async void (or Task) MyCaller()
{
await Task.Factory.StartNew(() => myMethod.Invoke(Activator.CreateInstance(myClass), myParams));
}
void or Task depends on which context you are in.
When you wait() a Task.Factory.StartNew() the result is a Task
Therefore you have to call wait() two times or you can use await operator.
Therefore you can do the following.
var invokedTask = Task.Factory.StartNew(() => myMethod.Invoke(Activator.CreateInstance(myClass), myParams));
var result=await await invokedTask;
Or you can do the following
var invokedTask = Task.Factory.StartNew(() => myMethod.Invoke(Activator.CreateInstance(myClass), myParams));
invokedTask.Wait();
var resultTask=invokedTask.Result;
resultTask.Wait();
var result=resultTask.Result;
However from the question you have posted, it looks like your myMethod.Invoke() returns Task.Factor.StartNew() therefore I would like you to try
var result =await await myMethod.Invoke(Activator.CreateInstance(myClass), myParams);
However it is a bad practice to use Wait() and then Result() as it block the current thread.
Therefore I would like you to use await.
This example may help:
public class MagicClass
{
private int magicBaseValue;
public MagicClass()
{
magicBaseValue = 9;
}
public Task<int> ItsMagic(int preMagic)
{
return Task.Factory.StartNew(() => preMagic * magicBaseValue);
}
}
public class TestMethodInfo
{
public static void Main()
{
// Get the ItsMagic method and invoke with a parameter value of 100
Type magicType = typeof(MagicClass);
MethodInfo magicMethod = magicType.GetMethod("ItsMagic");
var magicValue = ((Task<int>)(magicMethod.Invoke(Activator.CreateInstance(typeof(MagicClass)), new object[] { 100 }))).Result;
Console.WriteLine("MethodInfo.Invoke() Example\n");
Console.WriteLine("MagicClass.ItsMagic() returned: {0}", magicValue.ToString());
Console.ReadKey();
}
}
You can cast your Invoke as a Task<> and then get the Result. This will wait until the method is done executing.

Cancelling an entire task when a called method does not return

I have a method that registers a background task that looks like this:
//snippet from task builder method
try
{
cancellationTokenSource.CancelAfter(10000);
btr = Task.Run(() => registerTask(builder, btr,cancellationTokenSource.Token), cancellationTokenSource.Token).Result;
}
catch (OperationCanceledException) // something went wrong
{
return null;
}
private BackgroundTaskRegistration registerTask(BackgroundTaskBuilder builder, BackgroundTaskRegistration btr, CancellationToken token)
{
CancellationTokenSource newToken = new CancellationTokenSource();
Task cancelledCheck = Task.Run(() =>
{
while (true)
{
if (token.IsCancellationRequested)
{
newToken.Cancel();
token.ThrowIfCancellationRequested();
}
}
}, newToken.Token);
btr = Task.Run(()=> builder.Register(),token).Result;
return btr;
}
My issue is that sometimes the builder.Register() method does not return anything. It's probably a Windows bug of some sort; the Register() method never finishes internally. Indeed, after 10 seconds, the token.ThrowIfCancellationRequested() method is called, but it does not throw to the try-catch statement where it's called. Initially I was calling builder.Register() directly without a Task.Run() but it didn't work, and neither does this.
However, if I replace btr = Task.Run(() =>... with a Task.Delay(ms) instead, where ms > 10000, my intended effect happens.
Am I doing something wrong? Or is there a better way to do this? Basically I just need code that will make the registerTask() method return null when builder.Register() does not finish after a few seconds.
Replacing the code with something like this worked for me:
btr = null;
cancellationTokenSource.CancelAfter(10000);
Task registerTask = Task.Factory.StartNew(() =>
{
btr = builder.Register();
});
Task cancellationTask = Task.Factory.StartNew(() =>
{
while (true)
{
if (cancellationTokenSource.Token.IsCancellationRequested) break;
}
}, cancellationTokenSource.Token);
Task[] tasks = new Task[2] { cancellationTask, registerTask };
Task.WaitAny(tasks);
Instead of handling the error, getting a cancellation request will trigger one of the tasks to end, and when it ends I return the task registration variable whether it's null or not.

Correct way to link Tasks together when return values are needed at different times

I hope this makes sense - Suppose I have the following code:
Task.Run(() =>
{
return Task.WhenAll
(
Task1,
Task2,
...
Taskn
)
.ContinueWith(tsks=>
{
TaskA (uses output from Tasks Task1 & Task2, say)
}
, ct)
.ContinueWith(res =>
{
TaskB (uses output from TaskA and Task3, say)
}
, ct);
});
So I want all my first N tasks to run concurrently (since we have no interdependencies), then only once they're all finished, to continue with a task that relies on their outputs (I get that for this, I can use the tsks.Result).
BUT THEN I want to continue with a task that relies on one of the first tasks and the result of TaskA.
I'm a bit lost how to structure my code correctly so I can access the results of my first set of tasks outside of the immediately proceeding ContinueWith.
My one thought was to assign return value to them within my method - Something like:
... declare variables outside of Tasks ...
Task.Run(() =>
{
return Task.WhenAll
(
Task.Run(() => { var1 = Task1.Result; }, ct),
...
Task.Run(() => { varn = Taskn.Result; }, ct),
)
.ContinueWith(tsks=>
{
TaskA (uses output from Tasks var1 & varn, say)
}
, ct)
.ContinueWith(res =>
{
TaskB (uses output from TaskA and var3, say)
}
, ct);
});
But, even though this works for me, I have no doubt that that is doing it wrong.
What is the correct way? Should I have a state object that contains all the necessary variables and pass that throughout all my tasks? Is there a better way in total?
Please forgive my ignorance here - I'm just VERY new to concurrency programming.
Since Task1, Task2, ... , TaskN are in scope for the call of WhenAll, and because by the time ContinueWith passes control to your next task all the earlier tasks are guaranteed to finish, it is safe to use TaskX.Result inside the code implementing continuations:
.ContinueWith(tsks=>
{
var resTask1 = Task1.Result;
...
}
, ct)
You are guaranteed to get the result without blocking, because the task Task1 has finished running.
Here is a way to do it with ConcurrentDictionary, which sounds like it might be applicable in your use case. Also, since you're new to concurrency, it shows you the Interlocked class as well:
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Executing...");
var numOfTasks = 50;
var tasks = new List<Task>();
for (int i = 0; i < numOfTasks; i++)
{
var iTask = Task.Run(() =>
{
var counter = Interlocked.Increment(ref _Counter);
Console.WriteLine(counter);
if (counter == numOfTasks - 1)
{
Console.WriteLine("Waiting {0} ms", 5000);
Task.Delay(5000).Wait(); // to simulate a longish running task
}
_State.AddOrUpdate(counter, "Updated Yo!", (k, v) =>
{
throw new InvalidOperationException("This shouldn't occure more than once.");
});
});
tasks.Add(iTask);
}
Task.WhenAll(tasks)
.ContinueWith(t =>
{
var longishState = _State[numOfTasks - 1];
Console.WriteLine(longishState);
Console.WriteLine("Complete. longishState: " + longishState);
});
Console.ReadKey();
}
static int _Counter = -1;
static ConcurrentDictionary<int, string> _State = new ConcurrentDictionary<int, string>();
}
You get output similar to this (though it the Waiting line won't always be last before the continuation):
An elegant way to solve this is to use Barrier class.
Like this:
var nrOfTasks = ... ;
ConcurrentDictionary<int, ResultType> Results = new ConcurrentDictionary<int, ResultType>();
var barrier = new Barrier(nrOfTasks, (b) =>
{
// here goes the work of TaskA
// and immediatley
// here goes the work of TaskB, having the results of TaskA and any other task you might need
});
Task.Run(() => { Results[1] = Task1.Result; barrier.SignalAndWait(); }, ct),
...
Task.Run(() => { Results[nrOfTasks] = Taskn.Result; barrier.SignalAndWait(); }, ct

How do I run tasks in parallel and select the first result that satisfies a given condition in C#? [duplicate]

This question already has answers here:
TPL wait for task to complete with a specific return value
(2 answers)
Closed 7 years ago.
There are three tasks that I wish to run in parallel. I wish to examine the result of the first task that finished and do a check to decide if the result is good. If yes, I cancel all other tasks and return this result, if not, I will wait for next completed task and check if that is good and do the same if it is. (Think of being good as some simple check on a member of OutputDataType).
I continue this until I obtain a completed task with a good result, or all tasks return with results that are not good, in which case I return null.
Thank you in advance.
using System;
using System.Threading;
using System.Threading.Tasks;
namespace myNamespace
{
class Program
{
static void Main()
{
InputDataType data = getMyData();
OutputDataType x = Foo(data);
}
static OutputDataType Foo(InputDataType data)
{
Task<OutputDataType> task1 = null, task2 = null, taks3 = null;
Task<OutPutDataType>[] TaskArray = { task1, task2, task3 };
task1 = Task<SolutionInterpreters>.Factory.StartNew(() => RunFunc1(data));
task2 = Task<SolutionInterpreters>.Factory.StartNew(() => RunFunc2(data));
task3 = Task<SolutionInterpreters>.Factory.StartNew(() => RunFunc3(data));
/*
.
.
.
*/
}
}
}
In TPL, task cancellation is cooperative, so you need to define some means of indicating to your other tasks that they should stop executing. The most common way to do this is through CancellationTokenSource, whose token can be checked for cancellation within your RunFuncX methods.
static void Main()
{
InputDataType data = getMyData();
OutputDataType x = Foo(data).Result;
}
static async Task<OutputDataType> Foo(InputDataType data)
{
// Spawn your tasks, passing the cancellation token.
var cts = new CancellationTokenSource();
var task1 = Task.Factory.StartNew(() => RunFunc1(data, cts.Token));
var task2 = Task.Factory.StartNew(() => RunFunc2(data, cts.Token));
var task3 = Task.Factory.StartNew(() => RunFunc3(data, cts.Token));
var tasks = new [] { task1, task2, task3 };
// Loop while tasks are running.
while (tasks.Any())
{
// Wait for any task to complete.
var completedTask = await Task.WhenAny(tasks);
// If its result is good, indicate cancellation to the other tasks,
// and return the result.
if (IsResultGood(completedTask.Result))
{
cts.Cancel();
return completedTask.Result;
}
// Otherwise, remove the completed task from the array,
// and proceed to the next iteration.
tasks = tasks.Where(t => t != completedTask).ToArray();
}
// No good results.
return null;
}
Per Spo1ler's comment, I've updated your Foo method to an asynchronous implementation. This assumes you're using C# 5.0. When consuming the method, use await to get its result. If you're really running as a console application, your topmost call would need to block, so you can just get the task's Result.

C# Threaded Tasks - cannot get return value from array of tasks

I am attempting to get the return data from my task, it works ok if i use a single var, but when i use an array or arraylist, i do not see the interface for RESULT in the available properties methods of the task object.
var task = Task<BookingListResponse>
.Factory.StartNew(() => GetServicesFromApi(sc),
TaskCreationOptions.LongRunning);
tasks.Add(task);
try
{
// Wait for all the tasks to finish.
Task.WaitAll(tasks.ToArray());
}
as you can see from the code, if i put the tasks back into an array and type tasks[1].Result, it does not expose 'result', if i access task then i can get it.
I am sure i am doing something silly, so any help would be good.
cheers.
Paul.
here is the full code:
List<Task> tasks = new List<Task>();
// loop schemes and only call DISTINCT transit api URL's
foreach (Scheme scheme in schemes)
{
if (url.ContainsKey(scheme.Url))
continue;
url.Add(scheme.Url, 0); // add url.
var sc = new ServiceCriteria();
sc.Url = scheme.Url;
sc.CapacityRequirement = capacityRequirement;
sc.DropOffLocation = dropOffLocation;
sc.PickUpLocation = pickUpLocation;
sc.PickUp = pickup;
sc.TravelTime = travelTime;
// Fire off thread for each method call.
//tasks.Add(Task<BookingListResponse>.Factory.StartNew(apiAttributes =>
// GetServicesFromApi(sc), TaskCreationOptions.LongRunning));
var task = Task<BookingListResponse>
.Factory.StartNew(() => GetServicesFromApi(sc),
TaskCreationOptions.LongRunning);
tasks.Add(task);
}
try
{
// Wait for all the tasks to finish.
Task.WaitAll(tasks.ToArray());
var result = tasks[0].Result;
}
the result option does not show.
cheers.
You need to cast your list of Tasks into Task<BookingListResponse>...
So do:
var result = ((Task<BookingListResponse>)tasks[0]).Result;
task.Result
or
tasks.First().Result
should work

Categories

Resources