Task<Task> illegal in C#? - c#

This code gives a compile time error in VS2015
Error CS0266 Cannot implicitly convert type 'System.Threading.Tasks.Task' to 'System.Threading.Tasks.Task<System.Threading.Tasks.Task>'. An explicit conversion exists (are you missing a cast?)
UPDATE 1: extended code after a Task instead of Task< Task > was suggested.
int i = 0;
Task<int> test = Task.Run( () => {
return i;
} );
i = test.Result;
Task t = Task.Run( () => { } );
Task<Task> test2 = Task.Run( () => {
return t;
} );
t = test2.Result;
What am I doing wrong?
UPDATE 2:
This code gives a warning (and I want no warnings and no suppress pragmas)
Warning CS1998 This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.
int i = 0;
Task<int> test = Task.Run( () => {
return i;
} );
i = test.Result;
Task t = Task.Run( () => { } );
Task<Task> test2 = Task.Run( async () => {
return t;
} );
t = test2.Result;
UPDATE 3:
To all people insisting on Task test2.
StartAndReturnSecondTaskAsync must return the second task (executing longOperation2)
StartAndReturnSecondTaskAsync must be async, i.e. UI must not block for the duration of longOperation1
public static async Task<Task> StartAndReturnSecondTaskAsync() {
Task t = await Task.Run( () => {
return StartAndReturnSecondTask();
} );
return t;
}
public static Task StartAndReturnSecondTask() {
var importantData = longOperation1();
return Task.Run( () => {
longOperation2( importantData );
} );
}
...
Task second = await StartAndReturnSecondTaskAsync();

It's an extremely common but to use Task.Run to perform some asychronous operation, and if using the older method StartNew it would do what you're expecting, which is to schedule a thread pool thread to start the asynchronous operation, and tell you when that asynchronous operation has finished being started.
This is, however, basically never what people actually want. They want to know when the asynchronous operation called in Task.RUn finishes. Because of this, Task.Run will unwrap any Task<Task> that would be returned, so that what you're really seeing is the innerTask`.
If you really do just want to have a thread pool thread start the task, and just know when it has finished being started, then you can use Task.Factory.StartNew which does not unwrap the Task<Task> on your behalf.

Task<Task> are quite common and often a problem (if we erroneously wait/await wrong, outer task):
int i = 0;
Task<int> test = Task.Run(() => {
return i;
});
Task t = Task.Run(() => {
});
// please, notice "async"
Task<Task> test2 = Task.Run(async () => { // <- async: let insist on Task<Task>...
return t;
});
There's even an extension method for Task<Task>
Task backToTask = test2.Unwrap();
In your case you want
Task test2 = Task.Run(() => {
return t;
});
Since Task.Run calls Unwrap() for you

A simple solution without getting into much details:
The code that would work would be:
int i = 0;
Task<int> test = Task.Run(() =>
{
return i;
});
Task t = Task.Run(() => { });
Task test2 = Task.Run(() =>
{
return t;
});
If you go with other possible approaches that use await, You would need to make the context async, like:
public async Task DoesTheThreadedOperations()
{
// Your code in question and other code
}
As per your Update 3
public static async Task StartAndReturnSecondTaskAsync()
{
await Task.Run(() =>
{
return StartAndReturnSecondTask();
});
}
public static Task StartAndReturnSecondTask()
{
System.Threading.Thread.Sleep(5000);
return Task.Run(() =>
{
System.Threading.Thread.Sleep(10000);
});
}
I have used sleep to imitate your long operations. I hope you don't necessarily want to use Task<Task>. This should give you enough thrust to attack your scenario. You can further improve it to get your exact results by making these two operations two different threads and pass the results from one to other, await the one you want and run and leave the other longer task running without await. That is, call both methods from your main method, one awaited and other not.

Related

Why doesn't it work to use ContinueWith to run task sequentially?

My goal was to start "Task2" after "Task1". At first I wrote code like "Code1" below, but it did not work (Task2 started before Task1 was finished). So I searched Stackoverflow and modified my code like "Code2" below as the existing answer suggested. I wonder why "Code1" did not work.
Code1
static void Main(string[] args)
{
var p = new Program();
p.Test2();
Console.ReadKey();
}
void Test2()
{
Task.Factory.StartNew(async () =>
{
await Task1();
}).ContinueWith((t) => {
Task2();
});
}
async Task Task1()
{
Debug.WriteLine("Task 1 starting....");
await LongTask();
Debug.WriteLine("Task 1 done");
}
Task LongTask()
{
return Task.Factory.StartNew(() =>
{
Thread.Sleep(3000);
});
}
void Task2()
{
Debug.WriteLine("Task 2");
}
Code2
Task.Factory.StartNew(async () =>
{
await Task1();
Task2();
}).ContinueWith((t) => {
//Task2();
});
Because when you are running task like Task.Factory.StartNew(async () => ... it returns Task<Task> (task of task). And first task terminates without waiting for the inner Task.
For preventing this situation, you can use Unwrap method:
Task.Factory.StartNew(async () =>
{
await Task1();
})
.Unwrap()
.ContinueWith((t) => {
Task2();
});
That StartNew will return Task<Task>, and it seems you want to execute continuation after inner task completion. That's why we need Unwrap.
It “unwraps” the inner task that’s returned as the result of the outer task. Calling Unwrap on a Task gives you back a new Task (which we often refer to as a proxy) which represents the eventual completion of the inner task. And then, we are adding continuation to the inner task.
But, as Task.Run will do that unwrapping automatically you can use Task.Run in that case:
Task.Run(async () =>
{
await Task1();
})
.ContinueWith((t) => {
Task2();
});
And that can be simplified to:
Task.Run(async () =>
{
await Task1();
Task2();
});
Detailed information about diferences between Task.Run and Task.Factory.StartNew:
Read more here from Stephen Toub who is an engineer in the .Net team. The reason of decision in case of Task.Run:
Because we expect it to be so common for folks to want to offload work
to the ThreadPool, and for that work to use async/await, we decided to
build this unwrapping functionality into Task.Run.
By the way, as Stephen recommended just try to use Task.Run in most cases, but this in no way obsoletes Task.Factory.StartNew, there is still some places in which Task.Factory.StartNew must be used:
Task.Factory.StartNew still has many important (albeit more advanced)
uses. You get to control TaskCreationOptions for how the task
behaves. You get to control the scheduler for where the task should
be queued to and run. You get to use overloads that accept object
state, which for performance-sensitive code paths can be used to avoid
closures and the corresponding allocations. For the simple cases,
though, Task.Run is your friend.
Task.Factory.StartNew don't understand async lambdas. For Task.Factory.StartNew your lambda is just function returning Task. It doesn't automatically await that task. Also, note that using Task.Factory.StarNew and ContinueWith is discouraged in modern C# as it hard to use correctly (please read, "StartNew is Dangerous" by Stephen Cleary). You should use Task.Factory.StarNew or ContinueWith only if you can't do without them.
Instead, you can just use async/await one more time:
async Task Test2()
{
await Task1();
Task2();
}
or Task.Run:
async Task Test2()
{
return Task.Run(await () =>
{
await Task1();
Task2();
});
}
The second approach might be convenient if you want to make sure that your asynchronous Task1() is started on background thread.

Async/Await action within Task.Run()

Task.Run(()=>{}) puts the action delegate into the queue and returns the task .
Is there any benefit of having async/await within the Task.Run()?
I understand that Task.Run() is required since if we want to use await directly, then the calling method will need to be made Async and will affect the calling places.
Here is the sample code which has async await within Task.Run(). The full sample is provided here: Create pre-computed tasks.
Task.Run(async () => { await new WebClient().DownloadStringTaskAsync("");});
Alternatively this could have been done:
Task.Run(() => new WebClient().DownloadStringTaskAsync("").Result;);
Since both, Task.Run() and Await will queue the work and will be picked by the thread pool, could the async/await within the Task.Run() be a bit redundant?
Is there any benefit of having async/await within the Task.Run() ?
Yes. Task.Run runs some action on a thread-pool thread. If such action does some IO work and asynchronously waits for the IO operation to complete via await, then this thread-pool thread can be used by the system for other work while the IO operation is still running.
Example:
Task.Run( async () =>
{
DoSomeCPUIntensiveWork();
// While asynchronously waiting for this to complete,
// the thread is given back to the thread-pool
var io_result = await DoSomeIOOperation();
DoSomeOtherCPUIntensiveWork(io_result);
});
Is there any benefit of having async/await within the Task.Run()
An async method returns to the caller as soon as the first await is hit (that operates on a non-completed task). So if that first execution "streak" of an async method takes a long time Task.Run will alter behavior: It will cause the method to immediately return and execute that first "streak" on the thread-pool.
This is useful in UI scenarios because that way you can make 100% sure that you are not blocking the UI. Example: HttpWebRequestdoes DNS resolution synchronously even when you use one of the async methods (this is basically a library bug/design error). This can pause the UI thread. So you can use Task.Run to be 100% sure that the UI is never blocked for longer than a few microseconds.
So back to the original question: Why await inside a Task.Run body? For the same reason you normally await: To unblock the thread.
In the example that you linked the main thread is being blocked until the asynchronous operation is done. It's being blocked by calling Wait() (which by the way is generally a bad idea).
Let's have a look at the return from the DownloadStringAsync in the linked sample:
return Task.Run(async () =>
{
content = await new WebClient().DownloadStringTaskAsync(address);
cachedDownloads.TryAdd(address, content);
return content;
});
Why would you wrap this in a Task? Think about your options for a second. If you don't want to wrap this in a Task, how would you make sure the method returns a Task<string> and still have it work? You'd mark the method as async of course! However, if you mark your method as async and you call Wait on it, you'll most likely end up with a deadlock, since the main thread is waiting for the work to finish, and your blocking the main thread so it can't let you know it's done.
When marking a method as async, the state machine will run on the calling thread, in your example however, the state machine runs on a separate thread, meaning there is little to no work being done on the main thread.
Calling Async from Non-Async Methods
We do some stuff like that when we are trying to call an async method inside of a non-async method. Especially if the async method is a known quantity. We use more of a TaskFactory though ... fits a pattern, makes it easier to debug, makes sure everyone takes the same approach (and -- gives us one throat to choke if async-->sync starts acting buggy).
So, Your Example
Imagine, in your example, that you have a non-async function. And, within that function, you need to call await webClient.DoSomethingAsync(). You can't call await inside of a function that's not async -- the compiler won't let you.
Option 1: Zombie Infestation
Your first option is to crawl all the way back up your call stack, marking every da*n method along the way as async and adding awaits everywhere. Everywhere. Like, everywhere. Then -- since all those methods are now async, you need to make the methods that reference them all async.
This, btw, is probably the approach many of the SO enthusiasts are going to advocate. Because, "blocking a thread is a bad idea."
So. Yeah. This "let async be async" approach means your little library routine to get a json object just reached out and touched 80% of the code. Who's going to call the CTO and let him know?
Option 2: Just Go with the One Zombie
OR, you can encapsulate your async inside of some function like yours...
return Task.Run(async () => {
content = await new WebClient().DoSomethingAsync();
cachedDownloads.TryAdd(address, content);
return content;
});
Presto... the zombie infestation has been contained to a single section of code. I'll leave it to the bit-mechanics to argue over how/why that gets executed at the CPU-level. I don't really care. I care that nobody has to explain to the CTO why the entire library should now be 100% async (or something like that).
Confirmed, wrapping await with Task.Run use 2 threads instead of one.
Task.Run(async () => { //thread #1
await new WebClient().DownloadStringTaskAsync(""); //thread #2
});
Say you have four calls wrapped like this, it will use 4 x 2 = 8 threads.
It would be better to just call these with simple await instead. For example:
Task<byte[]> t1 = new WebClient().DownloadStringTaskAsync("");
Task<byte[]> t2 = new WebClient().DownloadStringTaskAsync("");
byte[] t1Result = await t1;
byte[] t2Result = await t2;
Here is the proof that wrapped Task.Run are using extra threads. (Not using WebClient to prove the point)
private static async Task wrapped()
{
List<Task> tasks = new List<Task>();
tasks.AddRange(new []
{
Task.Run(async() => await new MyThread().RunMe()),
Task.Run(async() => await new MyThread().RunMe()),
Task.Run(async() => await new MyThread().RunMe()),
Task.Run(async() => await new MyThread().RunMe()),
});
Thread.Sleep(1000);
int number = Process.GetCurrentProcess().Threads.Count;
Console.WriteLine($"While running thread count: {number}");
await Task.WhenAll(tasks);
}
Unwrapped
private static async Task unwrapped()
{
List<Task> tasks = new List<Task>();
Task<int> t1 = new MyThread().RunMe();
Task<int> t2 = new MyThread().RunMe();
Task<int> t3 = new MyThread().RunMe();
Task<int> t4 = new MyThread().RunMe();
tasks.AddRange(new[] {t1, t2, t3, t4});
Thread.Sleep(1000);
int number = Process.GetCurrentProcess().Threads.Count;
Console.WriteLine($"While running thread count: {number}");
int i1 = await t1;
int i2 = await t2;
int i3 = await t3;
int i4 = await t4;
}
Full POC code here
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
namespace AsyncThreadDemo
{
class Program
{
static async Task Main(string[] args)
{
int number = Process.GetCurrentProcess().Threads.Count;
Console.WriteLine($"Init thread count: {number}");
//await wrapped();
await unwrapped();
number = Process.GetCurrentProcess().Threads.Count;
Console.WriteLine($"Done thread count: {number}");
Console.ReadLine();
}
private static async Task wrapped()
{
List<Task> tasks = new List<Task>();
tasks.AddRange(new []
{
Task.Run(async() => await new MyThread().RunMe()),
Task.Run(async() => await new MyThread().RunMe()),
Task.Run(async() => await new MyThread().RunMe()),
Task.Run(async() => await new MyThread().RunMe()),
});
Thread.Sleep(1000);
int number = Process.GetCurrentProcess().Threads.Count;
Console.WriteLine($"While running thread count: {number}");
await Task.WhenAll(tasks);
}
private static async Task unwrapped()
{
List<Task> tasks = new List<Task>();
Task<int> t1 = new MyThread().RunMe();
Task<int> t2 = new MyThread().RunMe();
Task<int> t3 = new MyThread().RunMe();
Task<int> t4 = new MyThread().RunMe();
tasks.AddRange(new[] {t1, t2, t3, t4});
Thread.Sleep(1000);
int number = Process.GetCurrentProcess().Threads.Count;
Console.WriteLine($"While running thread count: {number}");
int i1 = await t1;
int i2 = await t2;
int i3 = await t3;
int i4 = await t4;
}
}
public class MyThread
{
public static int _counter;
public async Task<int> RunMe()
{
await Task.Run(() =>
{
for (int i = 0; i < 2; ++i)
{
Thread.Sleep(1000);
Console.WriteLine($"T{Thread.CurrentThread.ManagedThreadId} {i}");
}
Console.WriteLine($"T{Thread.CurrentThread.ManagedThreadId} done");
});
return _counter++;
}
}
}

Is it OK to do some async/await inside some .NET Parallel.ForEach() code?

Given the following code, is it OK to do async/await inside a Parallel.ForEach ?
eg.
Parallel.ForEach(names, name =>
{
// Do some stuff...
var foo = await GetStuffFrom3rdPartyAsync(name);
// Do some more stuff, with the foo.
});
or is there some gotcha's that I need to be made aware of?
EDIT: No idea if this compiles, btw. Just Pseduo-code .. thinking out loud.
No, It doesn't make sense to combine async with Paralell.Foreach.
Consider the following example:
private void DoSomething()
{
var names = Enumerable.Range(0,10).Select(x=> "Somename" + x);
Parallel.ForEach(names, async(name) =>
{
await Task.Delay(1000);
Console.WriteLine("Name {0} completed",name);
});
Console.WriteLine("Parallel ForEach completed");
}
What output you will expect?
Name Somename3 completed
Name Somename8 completed
Name Somename4 completed
...
Parallel ForEach completed
That's not what will happen. It will output :
Parallel ForEach completed
Name Somename3 completed
Name Somename8 completed
Name Somename4 completed
...
Why? Because when ForEach hits first await the method actually returns, Parallel.ForEach doesn't know it is asynchronous and it ran to completion!. Code after await runs as continuation on another thread not "Paralell processing thread"
Stephen toub addressed this here
From the name, I'm assuming that GetStuffFrom3rdPartyAsync is I/O-bound. The Parallel class is specifically for CPU-bound code.
In the asynchronous world, you can start multiple tasks and then (asynchronously) wait for them all to complete using Task.WhenAll. Since you're starting with a sequence, it's probably easiest to project each element to an asynchronous operation, and then await all of those operations:
await Task.WhenAll(names.Select(async name =>
{
// Do some stuff...
var foo = await GetStuffFrom3rdPartyAsync(name);
// Do some more stuff, with the foo.
}));
A close alternative might be this:
static void ForEach<T>(IEnumerable<T> data, Func<T, Task> func)
{
var tasks = data.Select(item =>
Task.Run(() => func(item)));
Task.WaitAll(tasks.ToArray());
}
// ...
ForEach(names, name => GetStuffFrom3rdPartyAsync(name));
Ideally, you shouldn't be using a blocking call like Task.WaitAll, if you can make the whole chain of methods calls async, "all the way down" on the current call stack:
var tasks = data.Select(item =>
Task.Run(() => func(item)));
await Task.WhenAll(tasks.ToArray());
Furthermore, if you don't do any CPU-bound work inside GetStuffFrom3rdPartyAsync, Task.Run may be redundant:
var tasks = data.Select(item => func(item));
As pointed out by #Sriram Sakthivel there are some problems with using Parallel.ForEach with asynchronous lambdas. Steven Toub's ForEachASync can do the equivalent. He talks about it here, but here is the code:
public static class Extensions
{
public static Task ForEachAsync<T>(this IEnumerable<T> source, int dop, Func<T, Task> body)
{
return Task.WhenAll(
from partition in Partitioner.Create(source).GetPartitions(dop)
select Task.Run(async delegate {
using (partition) while (partition.MoveNext()) await body(partition.Current);
}));
}
}
It uses the Partitioner class to create a load balancing partitioner(doco), and allows you to specify how many threads you want to run with the dop parameter. to see the difference between it and Parallel.ForEach. Try the following code.
class Program
{
public static async Task GetStuffParallelForEach()
{
var data = Enumerable.Range(1, 10);
Parallel.ForEach(data, async i =>
{
await Task.Delay(1000 * i);
Console.WriteLine(i);
});
}
public static async Task GetStuffForEachAsync()
{
var data = Enumerable.Range(1, 10);
await data.ForEachAsync(5, async i =>
{
await Task.Delay(1000 * i);
Console.WriteLine(i);
});
}
static void Main(string[] args)
{
//GetStuffParallelForEach().Wait(); // Finished printed before work is complete
GetStuffForEachAsync().Wait(); // Finished printed after all work is done
Console.WriteLine("Finished");
Console.ReadLine();
}
if you run GetStuffForEachAsync the program waits for all work to finish. If you run GetStuffParallelForEach, the line Finished will be printed before the work is finished.

Task.Factory.StartNew with parameters and return values

Trying to call a method that requires parameters in order to get a result and pass the result to proceed. But I'm new to the Task area and can't seem to figure out the correct syntax. Any help would be appreciated.
Task.Factory.StartNew(() =>
CheckConflict(startDate, endDate, actID, repeatRule,whichTime))
.ContinueWith(
GetConflictDelegate(result),
TaskScheduler.FromCurrentSynchronizationContext);
Assuming you want to continue with the result of CheckConflict(), ContinueWith takes a Task<T> as an argument. Task<T> has a property Result, which will be the result from the method invocation.
See my code snippet below, for an example.
new TaskFactory()
.StartNew(() =>
{
return 1;
})
.ContinueWith(x =>
{
//Prints out System.Threading.Tasks.Task`1[System.Int32]
Console.WriteLine(x);
//Prints out 1
Console.WriteLine(x.Result);
});
I recommend you use async/await:
var result = await Task.Run(
() => CheckConflict(startDate, endDate, actID, repeatRule, whichTime);
GetConflictDelegate(result);
Task.Factory.StartNew<TResult>(new Func<TResult>(() =>
{
return 1;
}).ContinueWith<TResult>(new Action((result) =>
{
Console.Writeline(result.Result); // output: 1
});
Try this one
You need the Task<TResult> class (see MSDN - TaskFactory.StartNew-Methode (Func, Object). <TResult> is the return type of your invoked method.
Because you starting a new thread you have to wait until thread is finished without blocking the main thread or leading the messagepump to stop. This is where you can use async and await.
Assuming a method Calculate() which is taking two parameters of type double and returning a result of double and a second method called Validate() which validates the result. The solution could look like this:
private async Task CalculateAsync()
{
// Our parameter object
CustomArgsObject customParameterObject = new CustomArgsObject()
{
Value1 = 500,
Value2 = 300
};
Task<double> returnTaskObject = await Task<double>.Factory.StartNew(
(paramsHoldingValues) => Calculate(paramsHoldingValues as CustomArgsObject),
customParameterObject);
// Because of await the following lines will only be executed
// after the task is completed while the caller thread still has 'focus'
double result = returnTaskObject.Result;
Validate(result);
}
private double Calculate(CustomArgsObject values)
{
return values.Value1 + values.Value2;
}
private bool Validate(double value)
{
return (value < 1000);
}
The await returns focus back to the the caller thread (thread who called CalculateAsync() ) to prevent locking while the task is running. At the same time await forces the CalculateAsync() to be processed until the line where the task is started and then waits until the task is completed. The the rest of the CalculateAsync() will then be processed.
Without await the whole method would be processed - before the task is finished or simultaneous to the running task.
The Task<TResult> class (where <TResult> is the placeholder for your return type) has a property Result that holds the return value of type <TResult>.
This works:
Task.Factory.StartNew(()=>
{
return CheckConflict(startDate, endDate, actID, repeatRule,whichTime);
}).ContinueWith(x=>
{
GetConflictDelegate(whichTime);
},TaskScheduler.FromCurrentSynchronizationContext());

Run "async" method on a background thread

I'm trying to run an "async" method from an ordinary method:
public string Prop
{
get { return _prop; }
set
{
_prop = value;
RaisePropertyChanged();
}
}
private async Task<string> GetSomething()
{
return await new Task<string>( () => {
Thread.Sleep(2000);
return "hello world";
});
}
public void Activate()
{
GetSomething.ContinueWith(task => Prop = task.Result).Start();
// ^ exception here
}
The exception thrown is:
Start may not be called on a continuation task.
What does that mean, anyway? How can I simply run my async method on a background thread, dispatch the result back to the UI thread?
Edit
Also tried Task.Wait, but the waiting never ends:
public void Activate()
{
Task.Factory.StartNew<string>( () => {
var task = GetSomething();
task.Wait();
// ^ stuck here
return task.Result;
}).ContinueWith(task => {
Prop = task.Result;
}, TaskScheduler.FromCurrentSynchronizationContext());
GetSomething.ContinueWith(task => Prop = task.Result).Start();
}
To fix your example specifically:
public void Activate()
{
Task.Factory.StartNew(() =>
{
//executes in thread pool.
return GetSomething(); // returns a Task.
}) // returns a Task<Task>.
.Unwrap() // "unwraps" the outer task, returning a proxy
// for the inner one returned by GetSomething().
.ContinueWith(task =>
{
// executes in UI thread.
Prop = task.Result;
}, TaskScheduler.FromCurrentSynchronizationContext());
}
This will work, but it's old-school.
The modern way to run something on a background thread and dispatch back to UI thread is to use Task.Run(), async, and await:
async void Activate()
{
Prop = await Task.Run(() => GetSomething());
}
Task.Run will start something in a thread pool thread. When you await something, it automatically comes back in on the execution context which started it. In this case, your UI thread.
You should generally never need to call Start(). Prefer async methods, Task.Run, and Task.Factory.StartNew -- all of which start the tasks automatically. Continuations created with await or ContinueWith are also started automatically when their parent completes.
WARNING about using FromCurrentSynchronizationContext:
Ok, Cory knows how to make me rewrite answer:).
So the main culprit is actually the FromCurrentSynchronizationContext!
Any time StartNew or ContinueWith runs on this kind scheduler, it runs on the UI Thread. One may think:
OK, let's start subsequent operations on UI, change some controls, spawn some operations. But from now TaskScheduler.Current is not null and if any control has some events, that spawn some StartNew expecting to be running on ThreadPool, then from there it goes wrong. UI aps are usually complex, unease to maintain certainty, that nothing will call another StartNew operation, simple example here:
public partial class Form1 : Form
{
public static int Counter;
public static int Cnt => Interlocked.Increment(ref Counter);
private readonly TextBox _txt = new TextBox();
public static void WriteTrace(string from) => Trace.WriteLine($"{Cnt}:{from}:{Thread.CurrentThread.Name ?? "ThreadPool"}");
public Form1()
{
InitializeComponent();
Thread.CurrentThread.Name = "ThreadUI!";
//this seems to be so nice :)
_txt.TextChanged += (sender, args) => { TestB(); };
WriteTrace("Form1"); TestA(); WriteTrace("Form1");
}
private void TestA()
{
WriteTrace("TestA.Begin");
Task.Factory.StartNew(() => WriteTrace("TestA.StartNew"))
.ContinueWith(t =>
{
WriteTrace("TestA.ContinuWith");
_txt.Text = #"TestA has completed!";
}, TaskScheduler.FromCurrentSynchronizationContext());
WriteTrace("TestA.End");
}
private void TestB()
{
WriteTrace("TestB.Begin");
Task.Factory.StartNew(() => WriteTrace("TestB.StartNew - expected ThreadPool"))
.ContinueWith(t => WriteTrace("TestB.ContinueWith1 should be ThreadPool"))
.ContinueWith(t => WriteTrace("TestB.ContinueWith2"));
WriteTrace("TestB.End");
}
}
Form1:ThreadUI! - OK
TestA.Begin:ThreadUI! - OK
TestA.End:ThreadUI! - OK
Form1:ThreadUI! - OK
TestA.StartNew:ThreadPool - OK
TestA.ContinuWith:ThreadUI! - OK
TestB.Begin:ThreadUI! - OK
TestB.End:ThreadUI! - OK
TestB.StartNew - expected ThreadPool:ThreadUI! - COULD BE UNEXPECTED!
TestB.ContinueWith1 should be ThreadPool:ThreadUI! - COULD BE UNEXPECTED!
TestB.ContinueWith2:ThreadUI! - OK
Please notice, that tasks returned by:
async method,
Task.Fatory.StartNew,
Task.Run,
can not be started! They are already hot tasks...

Categories