Originally, Start (and the task constructors) were intended so that developers could define tasks to be executed kind of like a fancy delegate. Then, other code could execute those tasks in whatever way it felt appropriate (e.g., on the UI thread, or on a background thread). But in the real world, this is almost never useful, because what the delegate does usually determines its required context (e.g., a delegate accessing UI elements must be run on the UI thread). So this separation doesn’t make sense for most code, and even when it does, developers just use delegates directly instead of tasks.

Start can only be called on a task that is created with the task constructor; that is, it only works on Delegate Tasks that are in the Created state. Once Start is called, the task moves to the WaitingToRun state (and never returns to the Created state), so Start cannot be called on a task more than once. Start cannot be called on Promise Tasks at all, since they are never in the Created state.

In modern code - even dynamic task parallel code - Start just doesn’t have a place anymore. Instead of the task constructor and Start, use Task.Run, which creates and schedules a task.

RunSynchronously

RunSynchronously is very similar to Start, and has the same overloads:

voidRunSynchronously();voidRunSynchronously(TaskScheduler);

RunSynchronously will attempt to start the task immediately and execute it on the current thread. This does not always happen, however; the final decision is up to the task scheduler that is passed to RunSynchronously. For example, a task scheduler for the UI thread will not permit a task to run on a thread pool thread. If the task scheduler refuses to execute the task synchronously, then RunSynchronously behaves just like Start; that is, the task is queued to the task scheduler for future execution. Also just like Start, RunSynchronously can only be called on a task that is in the Created state, and can only be called on a task once.

Once again, the default TaskSchedler is TaskScheduler.Current. However, this time this behavior does make sense: since RunSynchronously will attempt to execute the task’s delegate on the current thread, it is reasonable to assume the current task scheduler is the correct one to use.

Similarly to Start, RunSynchronously doesn’t have any place in modern code.

IAsyncResult.CompletedSynchronously

Task has an explicit interface implementation of a member called CompletedSynchronously:

boolIAsyncResult.CompletedSynchronously{get;}

If you believe the MSDN documentation, this member should return true if the task was completed synchronously. Unfortunately, this member actually always returns false, even for synchronously-completed Promise Tasks such as those returned from Task.FromResult.

IAsyncResult.CompletedSynchronously is used by some legacy IAsyncResult-based code. But generally speaking, this member shouldn’t be used in modern code. In particular, you can’t depend on it being anything other than false for tasks.