Start may not be called on a promise-style task. exception is coming
You are getting that error because the Task
class already started the task before giving it to you. You should only ever call Start
on a task that you create by calling its constructor, and you shouldn't even do that unless you have a compelling reason to not start the task when you create it; if you want it started right away you should use Task.Run
or Task.Factory.StartNew
to both create and start a new Task
.
So, now we know to just get rid of that pesky Start
. You'll run your code and find that the message box is shown right away, not 5 seconds later, what's up with that?
Well, Task.Delay
just gives you a task that will be completed in 5 seconds. It doesn't stop execution of the thread for 5 seconds. What you want to do is have some code that's executed after that task finishes. That's what ContinueWith
is for. It lets you run some code after a given task is done:
public void FunctionA()
{
Task.Delay(5000)
.ContinueWith(t =>
{
MessageBox.Show("Waiting Complete");
});
}
This will behave as expected.
We could also leverage C# 5.0's await
keyword to add continuations more easily:
public async Task FunctionA()
{
await Task.Delay(5000);
MessageBox.Show("Waiting Complete");
}
While a full explanation of what's going on here is beyond the scope of this question, the end result is a method that behaves very similar to the previous method; it will show a message box 5 seconds after you call the method, but the method itself will return [almost] right away in both cases. That said, await
is very powerful, and allows us to write methods that seem simple and straightforward, but that would be much harder and messier to write using ContinueWith
directly. It also greatly simplifies dealing with error handling, taking out a lot of boilerplate code.
How to make sure a task is started and safely start it if not?
If for whatever reason you cannot change the code to not return unstarted tasks, you can check Status
and start task if it has Created
status:
if (task.Status == TaskStatus.Created)
task.Start();
All other task statues indicate that task is either completed, running, or being scheduled, so you don't need to start tasks in that statuses.
Of course in theory this introduces race condition, because task can be started right between your check and Start
call, but, as correctly pointed by Servy in comments - if there ever is race condition here - that means another party (which created that task) is also trying to start it. Even if you handle exception (InvalidOperationException
) - another party is unlikely to do that, and so will get exception while trying to start their own task. So only one side (either you, or code that created that task) should be trying to start it.
That said - much better than doing this is to ensure you might never get unstarted task in the first place, because it's just bad design to return such tasks to external code, at least without explicitly indicating that (while it's for some use cases ok to use unstarted task internally).
Getting error on foo.Start() when using Task.WhenAll for multiple tasks
await Task.WhenAll(
dashboardDailyAgeAnalysis, dashboardDailyBalance, dashboardDailyInventory
);
// Do something with these results.
var result1 = await dashboardDailyAgeAnalysis;
var result2 = await dashboardDailyBalance;
var result3 = await dashboardDailyInventory;
How to compose a unit test if a task is followed by task.start()?
The Task.Start
method can only be called on "cold" tasks, in other words on tasks that have not been started yet. Such tasks can only be created with the Task
constructor. Tasks created by invoking asynchronous methods implemented with the async
keyword are "hot", in other words they are already started upon creation. From the docs:
Exceptions
InvalidOperationException
TheTask
is not in a valid state to be started. It may have already been started, executed, or canceled, or it may have been created in a manner that doesn't support direct scheduling.
This is also a good reading: A Tour of Task, Part 10: Promise Tasks
C# starting tasks to run async methods
How can I start a task to await an async action?
In the TAP, tasks are returned "hot". So you literally just need to call the method and keep the task it returns:
private ConcurrentDictionary<int, Task> Tasks { get; set; }
private async Task StartTasks()
{
for(int i = 0; i < 5; i++)
{
Task task = DoWork(null);
Tasks.TryAdd(task.Id, task);
}
}
I cannot use Task.Run() since that does not provide TaskCreationOptions. These tasks will run for literal days.
You don't need TaskCreationOptions
. The LongRunning
flag is just a hint, and the thread pool will recover within a couple of seconds even if you don't specify that hint. But that doesn't even matter, because your work is asynchronous so it doesn't need to run on the thread pool in the first place.
TPL Producer consumer pattern - Start may not be called on a task that was already started
Remove the call to Start()
. Since StartNew()
starts the task it creates, there's no need for the Start()
.
Executing Tasks in Parallel - Silverlight
"Start may not be called on a promise-style task." is a somewhat misleading message for the simple thing: the task has already been started.
Thus, you may just omit the first loop.
Silverlight does not have Task.WhenAll
, but if you are using Microsoft.Bcl.Async
, it contains TaskEx.WhenAll
which is the same.
await TaskEx.WhenAll(displayThumbnailTasks);
Execute parallel tasks with async/await
Related Topics
How to Catch All Exceptions/Crashes in a .Net App
Datagridview: How to Set a Cell in Editing Mode
Convert Datetime to Julian Date in C# (Tooadate Safe)
How to Xml-Serialize a Dictionary
How to Get the Value of Private Field Using Reflection
Linq Join Iquery, How to Use Defaultifempty
Visual Studio Displaying Errors Even If Projects Build
How to Use Npm with ASP.NET Core
How Can Xml Documentation for Web API Include Documentation from Beyond the Main Project
Could Not Load File or Assembly 'System.Web.Http 4.0.0 After Update from 2012 to 2013
Should I Take Ilogger, Ilogger<T>, Iloggerfactory or Iloggerprovider for a Library