public void Wait() { if (scheduler == null) { schedWait.Wait(); } if (!IsCompleted) { scheduler.ParticipateUntil(this); } if (exception != null) { throw exception; } if (IsCanceled) { throw new AggregateException(new TaskCanceledException(this)); } }
public bool Wait(int millisecondsTimeout, CancellationToken cancellationToken) { if (millisecondsTimeout < -1) { throw new ArgumentOutOfRangeException("millisecondsTimeout"); } bool result = IsCompleted; if (!result) { if (scheduler == null) { Watch watch = Watch.StartNew(); schedWait.Wait(millisecondsTimeout, cancellationToken); millisecondsTimeout = ComputeTimeout(millisecondsTimeout, watch); } var wait_event = new ManualResetEventSlim(false); CancellationTokenRegistration?registration = null; try { if (cancellationToken.CanBeCanceled) { registration = cancellationToken.Register(wait_event.Set); } // FIXME: The implementation is wrong and slow // It adds a continuation to the task which is then // returned to parent causing all sort of problems when // timeout is reached before task is finished result = !scheduler.ParticipateUntil(this, wait_event, millisecondsTimeout); } finally { if (registration.HasValue) { registration.Value.Dispose(); } } } if (IsCanceled) { throw new AggregateException(new TaskCanceledException(this)); } if (exception != null) { throw exception; } return(result); }
public static int WaitAny(Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken) { if (tasks == null) { throw new ArgumentNullException("tasks"); } if (tasks.Length == 0) { throw new ArgumentException("tasks is empty", "tasks"); } if (tasks.Length == 1) { tasks[0].Wait(millisecondsTimeout, cancellationToken); return(0); } int numFinished = 0; int indexFirstFinished = -1; int index = 0; TaskScheduler sched = null; Task task = null; Watch watch = Watch.StartNew(); ManualResetEventSlim predicateEvt = new ManualResetEventSlim(false); foreach (Task t in tasks) { int indexResult = index++; t.ContinueWith(delegate { if (numFinished >= 1) { return; } int result = Interlocked.Increment(ref numFinished); // Check if we are the first to have finished if (result == 1) { indexFirstFinished = indexResult; } // Stop waiting predicateEvt.Set(); }, TaskContinuationOptions.ExecuteSynchronously); if (sched == null && t.scheduler != null) { task = t; sched = t.scheduler; } } // If none of task have a scheduler we are forced to wait for at least one to start if (sched == null) { var handles = Array.ConvertAll(tasks, t => t.schedWait.WaitHandle); int shandle = -1; if ((shandle = WaitHandle.WaitAny(handles, millisecondsTimeout)) == WaitHandle.WaitTimeout) { return(-1); } sched = tasks[shandle].scheduler; task = tasks[shandle]; millisecondsTimeout = ComputeTimeout(millisecondsTimeout, watch); } // One task already finished if (indexFirstFinished != -1) { return(indexFirstFinished); } if (cancellationToken != CancellationToken.None) { cancellationToken.Register(predicateEvt.Set); cancellationToken.ThrowIfCancellationRequested(); } sched.ParticipateUntil(task, predicateEvt, millisecondsTimeout); // Index update is still not done if (indexFirstFinished == -1) { SpinWait wait = new SpinWait(); while (indexFirstFinished == -1) { wait.SpinOnce(); } } return(indexFirstFinished); }