示例#1
0
        /// <summary>
        ///     Adds a new wait for the specified <paramref name="key"/> and with the specified <paramref name="timeout"/>.
        /// </summary>
        /// <typeparam name="T">The wait result type.</typeparam>
        /// <param name="key">A unique WaitKey for the wait.</param>
        /// <param name="timeout">The wait timeout.</param>
        /// <param name="cancellationToken">The cancellation token for the wait.</param>
        /// <returns>A Task representing the wait.</returns>
        public Task <T> Wait <T>(WaitKey key, int?timeout = null, CancellationToken?cancellationToken = null)
        {
            timeout = timeout ?? DefaultTimeout;

            var wait = new PendingWait()
            {
                TaskCompletionSource = new TaskCompletionSource <T>(TaskCreationOptions.RunContinuationsAsynchronously),
                DateTime             = DateTime.UtcNow,
                TimeoutAfter         = (int)timeout,
                CancellationToken    = cancellationToken,
            };

            var recordLock = Locks.GetOrAdd(key, new ReaderWriterLockSlim());

            recordLock.EnterReadLock();

            try
            {
                Waits.AddOrUpdate(key, new ConcurrentQueue <PendingWait>(new[] { wait }), (_, queue) =>
                {
                    queue.Enqueue(wait);
                    return(queue);
                });
            }
            finally
            {
                recordLock.ExitReadLock();
            }

            return(((TaskCompletionSource <T>)wait.TaskCompletionSource).Task);
        }
示例#2
0
        /// <summary>
        ///     Adds a new wait for the specified <paramref name="key"/> and with the specified <paramref name="timeout"/>.
        /// </summary>
        /// <typeparam name="T">The wait result type.</typeparam>
        /// <param name="key">A unique WaitKey for the wait.</param>
        /// <param name="timeout">The wait timeout.</param>
        /// <param name="cancellationToken">The cancellation token for the wait.</param>
        /// <returns>A Task representing the wait.</returns>
        public Task <T> Wait <T>(WaitKey key, int?timeout = null, CancellationToken?cancellationToken = null)
        {
            timeout = timeout ?? DefaultTimeout;

            var wait = new PendingWait()
            {
                TaskCompletionSource = new TaskCompletionSource <T>(TaskCreationOptions.RunContinuationsAsynchronously),
                DateTime             = DateTime.UtcNow,
                TimeoutAfter         = (int)timeout,
                CancellationToken    = cancellationToken,
            };

            Waits.AddOrUpdate(key, new ConcurrentQueue <PendingWait>(new[] { wait }), (_, queue) =>
            {
                queue.Enqueue(wait);
                return(queue);
            });

            return(((TaskCompletionSource <T>)wait.TaskCompletionSource).Task);
        }
示例#3
0
        /// <summary>
        ///     Adds a new wait for the specified <paramref name="key"/> and with the specified <paramref name="timeout"/>.
        /// </summary>
        /// <typeparam name="T">The wait result type.</typeparam>
        /// <param name="key">A unique WaitKey for the wait.</param>
        /// <param name="timeout">The wait timeout, in milliseconds.</param>
        /// <param name="cancellationToken">The cancellation token for the wait.</param>
        /// <returns>A Task representing the wait.</returns>
        public Task <T> Wait <T>(WaitKey key, int?timeout = null, CancellationToken?cancellationToken = null)
        {
            timeout ??= DefaultTimeout;
            cancellationToken ??= CancellationToken.None;

            var taskCompletionSource = new TaskCompletionSource <T>(TaskCreationOptions.RunContinuationsAsynchronously);

            var wait = new PendingWait(
                taskCompletionSource,
                timeout.Value,
                cancelAction: () => Cancel(key),
                timeoutAction: () => Timeout(key),
                cancellationToken.Value);

            // obtain a read lock for the key. this is necessary to prevent this code from adding a wait to the ConcurrentQueue
            // while the containing dictionary entry is being cleaned up in Disposition(), effectively discarding the new wait.
#pragma warning disable IDE0067, CA2000 // Dispose objects before losing scope
            var recordLock = Locks.GetOrAdd(key, new ReaderWriterLockSlim());
#pragma warning restore IDE0067, CA2000 // Dispose objects before losing scope

            recordLock.EnterReadLock();

            try
            {
                Waits.AddOrUpdate(key, new ConcurrentQueue <PendingWait>(new[] { wait }), (_, queue) =>
                {
                    queue.Enqueue(wait);
                    return(queue);
                });
            }
            finally
            {
                recordLock.ExitReadLock();
            }

            // defer registration to prevent the wait from being dispositioned prior to being successfully queued this is a
            // concern if we are given a timeout of 0, or a cancellation token which is already cancelled
            wait.Register();
            return(((TaskCompletionSource <T>)wait.TaskCompletionSource).Task);
        }