网上演练
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

311 lines
11 KiB

#if NET20 || NET30 || NET35 || !NET_4_6
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Runtime.CompilerServices;
using System.Runtime.ExceptionServices;
using LinqInternal.Core;
namespace System.Threading.Tasks
{
public partial class Task
{
private Action _promiseCheck = ActionHelper.GetNoopAction();
internal Task(TaskStatus taskStatus, InternalTaskOptions internalTaskOptions)
{
_status = (int)taskStatus;
_internalOptions = internalTaskOptions;
ExecutingTaskScheduler = TaskScheduler.Default;
}
internal Task()
{
_status = (int)TaskStatus.WaitingForActivation;
_internalOptions = InternalTaskOptions.PromiseTask;
ExecutingTaskScheduler = TaskScheduler.Default;
}
internal Task(object state, TaskCreationOptions creationOptions)
{
if ((creationOptions & ~(TaskCreationOptions.AttachedToParent | TaskCreationOptions.RunContinuationsAsynchronously)) != 0)
{
throw new ArgumentOutOfRangeException("creationOptions");
}
// Only set a parent if AttachedToParent is specified.
if ((creationOptions & TaskCreationOptions.AttachedToParent) != 0)
{
_parent = InternalCurrent;
}
State = state;
_creationOptions = creationOptions;
_status = (int)TaskStatus.WaitingForActivation;
_internalOptions = InternalTaskOptions.PromiseTask;
ExecutingTaskScheduler = TaskScheduler.Default;
}
public static Task FromCanceled(CancellationToken cancellationToken)
{
return FromCancellation(cancellationToken);
}
public static Task<TResult> FromCanceled<TResult>(CancellationToken cancellationToken)
{
return FromCancellation<TResult>(cancellationToken);
}
public static Task<TResult> FromResult<TResult>(TResult result)
{
return new Task<TResult>(TaskStatus.RanToCompletion, InternalTaskOptions.DoNotDispose)
{
CancellationToken = default(CancellationToken),
InternalResult = result
};
}
internal static Task<TResult> FromCancellation<TResult>(CancellationToken token)
{
var result = new Task<TResult>(TaskStatus.WaitingForActivation, InternalTaskOptions.PromiseTask)
{
CancellationToken = token,
ExecutingTaskScheduler = TaskScheduler.Default
};
if (token.IsCancellationRequested)
{
result.InternalCancel(false);
}
else if (token.CanBeCanceled)
{
token.Register(() => result.InternalCancel(false));
}
return result;
}
internal static Task FromCancellation(CancellationToken token)
{
var result = new Task(TaskStatus.WaitingForActivation, InternalTaskOptions.PromiseTask)
{
CancellationToken = token,
ExecutingTaskScheduler = TaskScheduler.Default
};
if (token.IsCancellationRequested)
{
result.InternalCancel(false);
}
else if (token.CanBeCanceled)
{
token.Register(() => result.InternalCancel(false));
}
return result;
}
internal bool SetCompleted(bool preventDoubleExecution)
{
// For this method to be called the Task must have been scheduled,
// this means that _status must be at least TaskStatus.WaitingForActivation (1),
// if status is:
// TaskStatus.WaitingForActivation (1) -> ok
// WaitingToRun (2) -> ok
// TaskStatus.Running (3) -> ok if preventDoubleExecution = false
// TaskStatus.WaitingForChildrenToComplete (4) -> ok if preventDoubleExecution = false
// TaskStatus.RanToCompletion (5) -> ok if preventDoubleExecution = false
// TaskStatus.Canceled (6) -> not ok
// TaskStatus.Faulted (7) -> -> ok if preventDoubleExecution = false
var spinWait = new SpinWait();
while (true)
{
var lastValue = Thread.VolatileRead(ref _status);
if ((preventDoubleExecution && lastValue >= 3) || lastValue == 6)
{
return false;
}
var tmp = Interlocked.CompareExchange(ref _status, 5, lastValue);
if (tmp == lastValue)
{
return true;
}
spinWait.SpinOnce();
}
}
internal void SetPromiseCheck(Action value)
{
_promiseCheck = value ?? ActionHelper.GetNoopAction();
}
internal bool TrySetCanceled(CancellationToken cancellationToken)
{
if (IsCompleted)
{
return false;
}
CancellationToken = cancellationToken;
try
{
// If an unstarted task has a valid CancellationToken that gets signalled while the task is still not queued
// we need to proactively cancel it, because it may never execute to transition itself.
// The only way to accomplish this is to register a callback on the CT.
if (cancellationToken.IsCancellationRequested)
{
// Fast path for an already-canceled cancellationToken
InternalCancel(false);
}
else
{
// Regular path for an uncanceled cancellationToken
var registration = cancellationToken.Register(_taskCancelCallback, this);
_cancellationRegistration = new StrongBox<CancellationTokenRegistration>(registration);
}
return true;
}
catch (Exception)
{
// If we have an exception related to our CancellationToken, then we need to subtract ourselves
// from our parent before throwing it.
if
(
(_parent != null)
&& ((_creationOptions & TaskCreationOptions.AttachedToParent) != 0)
&& ((_parent._creationOptions & TaskCreationOptions.DenyChildAttach) == 0)
)
{
_parent.DisregardChild();
}
throw;
}
}
internal bool TrySetCanceledPromise(CancellationToken tokenToRecord)
{
Contract.Assert(Action == null);
var returnValue = false;
Contract.Assert(IsPromiseTask, "Task.RecordInternalCancellationRequest(CancellationToken) only valid for promise-style task");
Contract.Assert(CancellationToken == default(CancellationToken));
if (tokenToRecord != default(CancellationToken))
{
CancellationToken = tokenToRecord;
}
returnValue |= InternalCancel(false);
return returnValue;
}
internal bool TrySetException(Exception exception)
{
AddException(exception);
var status = Interlocked.CompareExchange(ref _status, (int)TaskStatus.Faulted, (int)TaskStatus.WaitingForActivation);
var succeeded = status == (int)TaskStatus.WaitingForActivation;
if (succeeded)
{
MarkCompleted();
FinishStageThree();
}
return succeeded;
}
internal bool TrySetException(IEnumerable<Exception> exceptions)
{
foreach (var exception in exceptions)
{
AddException(exception);
}
var status = Interlocked.CompareExchange(ref _status, (int)TaskStatus.Faulted, (int)TaskStatus.WaitingForActivation);
var succeeded = status == (int)TaskStatus.WaitingForActivation;
if (succeeded)
{
MarkCompleted();
FinishStageThree();
}
return succeeded;
}
internal bool TrySetException(IEnumerable<ExceptionDispatchInfo> exceptions)
{
foreach (var exception in exceptions)
{
AddException(exception);
}
var status = Interlocked.CompareExchange(ref _status, (int)TaskStatus.Faulted, (int)TaskStatus.WaitingForActivation);
var succeeded = status == (int)TaskStatus.WaitingForActivation;
if (succeeded)
{
MarkCompleted();
FinishStageThree();
}
return succeeded;
}
private static Task CreateCompletedTask()
{
return new Task(TaskStatus.RanToCompletion, InternalTaskOptions.DoNotDispose)
{
CancellationToken = default(CancellationToken)
};
}
private void PromiseCheck()
{
_promiseCheck.Invoke();
}
}
public partial class Task<TResult>
{
internal Task(TaskStatus taskStatus, InternalTaskOptions internalTaskOptions)
: base(taskStatus, internalTaskOptions)
{
// Empty
}
internal Task()
{
// Empty
}
internal Task(object state, TaskCreationOptions creationOptions)
: base(state, creationOptions)
{
// Empty
}
public new static Task<TResult> FromCancellation(CancellationToken token)
{
var result = new Task<TResult>(TaskStatus.WaitingForActivation, InternalTaskOptions.PromiseTask)
{
CancellationToken = token,
ExecutingTaskScheduler = TaskScheduler.Default
};
if (token.IsCancellationRequested)
{
result.InternalCancel(false);
}
else if (token.CanBeCanceled)
{
token.Register(() => result.InternalCancel(false));
}
return result;
}
internal bool TrySetResult(TResult result)
{
if (IsFaulted)
{
return false;
}
if (IsCanceled)
{
return false;
}
if (SetCompleted(true))
{
InternalResult = result;
MarkCompleted();
FinishStageThree();
return true;
}
return false;
}
}
}
#endif