示例#1
0
        /// <summary>
        /// Sets up a simple process that distributes the input to the output channels
        /// </summary>
        /// <returns>An awaitable task.</returns>
        /// <param name="input">The data source.</param>
        /// <param name="output">The channels to distribute the data to.</param>
        /// <typeparam name="T">The 1st type parameter.</typeparam>
        public static Task ScatterAsync <T>(IReadChannel <T> input, IWriteChannel <T>[] output, ScatterGatherPolicy policy = ScatterGatherPolicy.Any)
        {
            if (input == null)
            {
                throw new ArgumentNullException(nameof(input));
            }
            if (output == null || output.Any(x => x == null))
            {
                throw new ArgumentNullException(nameof(output));
            }

            return(AutomationExtensions.RunTask(
                       new { Input = input, Output = output },
                       async self =>
            {
                if (policy == ScatterGatherPolicy.Any)
                {
                    while (true)
                    {
                        await MultiChannelAccess.WriteToAnyAsync(await self.Input.ReadAsync(), self.Output);
                    }
                }
                else
                {
                    var ix = 0;
                    while (true)
                    {
                        await self.Output[ix].WriteAsync(await self.Input.ReadAsync());
                        ix = (ix + 1) % output.Length;
                    }
                }
            }
                       ));
        }
示例#2
0
 /// <summary>
 /// Reads from any channel
 /// </summary>
 /// <param name="timeout">The maximum time to wait for a result.</param>
 public Task <MultisetResult <T> > ReadFromAnyAsync(TimeSpan timeout)
 {
     if (m_priority == MultiChannelPriority.Fair)
     {
         return(MultiChannelAccess.ReadFromAnyAsync(
                    m_sortedChannels.NotifyUsed,
                    m_sortedChannels.Channels,
                    timeout,
                    MultiChannelPriority.First
                    ));
     }
     else
     {
         return(MultiChannelAccess.ReadFromAnyAsync(
                    null,
                    m_channels,
                    timeout,
                    m_priority
                    ));
     }
 }
示例#3
0
 /// <summary>
 /// Writes to any of the channels.
 /// </summary>
 /// <param name="value">The value to write into the channel.</param>
 /// <param name="timeout">The maximum time to wait for any channel to become ready.</param>
 public Task <IWriteChannel <T> > WriteToAnyAsync(T value, TimeSpan timeout)
 {
     if (m_priority == MultiChannelPriority.Fair)
     {
         return(MultiChannelAccess.WriteToAnyAsync(
                    m_sortedChannels.NotifyUsed,
                    value,
                    m_sortedChannels.Channels,
                    timeout,
                    MultiChannelPriority.First
                    ));
     }
     else
     {
         return(MultiChannelAccess.WriteToAnyAsync(
                    null,
                    value,
                    m_channels,
                    timeout,
                    m_priority
                    ));
     }
 }
示例#4
0
        /// <summary>
        /// Reads or writes any of the specified requests
        /// </summary>
        /// <param name="callback">The method to call when the read completes, or null.</param>
        /// <param name="requests">The list of requests.</param>
        /// <param name="timeout">The maximum time to wait for a value to read.</param>
        /// <param name="priority">The priority used to select a channel, if multiple channels have a value that can be read.</param>
        public static Task <IMultisetRequestUntyped> ReadOrWriteAnyAsync(Action <object> callback, IEnumerable <IMultisetRequestUntyped> requests, TimeSpan timeout, MultiChannelPriority priority)
        {
            var tcs = new TaskCompletionSource <IMultisetRequestUntyped>();

            // We only accept the first offer
            var offer = new SingleOffer <IMultisetRequestUntyped>(tcs, timeout == Timeout.Infinite ? Timeout.InfiniteDateTime : DateTime.Now + timeout);

            offer.SetCommitCallback(callback);

            switch (priority)
            {
            case MultiChannelPriority.Fair:
                throw new Exception(string.Format("Construct a {0} or {1} object to use fair multichannel operations", typeof(MultiChannelSetRead <>).Name, typeof(MultiChannelSetWrite <>).Name));

            case MultiChannelPriority.Random:
                requests = MultiChannelAccess.Shuffle(requests);
                break;

            default:
                // Use the order the input has
                break;
            }

            // Keep a map of awaitable items
            var tasks = new Dictionary <Task, IMultisetRequestUntyped>();

            // Then we register the intent to read from a channel in order
            foreach (var c in requests)
            {
                // Timeout is handled by offer instance
                if (c.IsRead)
                {
                    tasks[c.Channel.ReadAsync(Timeout.Infinite, offer)] = c;
                }
                else
                {
                    tasks[c.Channel.WriteAsync(c.Value, Timeout.Infinite, offer)] = c;
                }

                // Fast exit to avoid littering the channels if we are done
                if (offer.IsTaken)
                {
                    break;
                }
            }

            offer.ProbePhaseComplete();

            if (tasks.Count == 0)
            {
                tcs.TrySetException(new InvalidOperationException("List of channels was empty"));
                return(tcs.Task);
            }

            tasks.Keys.WhenAnyNonCancelled().ContinueWith(item => Task.Run(() =>
            {
                if (item.IsCanceled)
                {
                    tcs.TrySetCanceled();
                    return;
                }
                else if (item.IsFaulted)
                {
                    tcs.TrySetException(item.Exception);
                    return;
                }

                if (offer.AtomicIsFirst())
                {
                    var n = item.Result;

                    // Figure out which item was found
                    if (n.IsCanceled)
                    {
                        tcs.SetCanceled();
                    }
                    else if (n.IsFaulted)
                    {
                        // Unwrap aggregate exceptions
                        if (n.Exception is AggregateException && (n.Exception as AggregateException).Flatten().InnerExceptions.Count == 1)
                        {
                            tcs.SetException(n.Exception.InnerException);
                        }
                        else
                        {
                            tcs.SetException(n.Exception);
                        }
                    }
                    else
                    {
                        var orig = tasks[n];
                        if (orig.IsRead)
                        {
                            orig.Value = ((Task <object>)n).Result;
                            tcs.SetResult(orig);
                        }
                        else
                        {
                            orig.Value = null;
                            tcs.SetResult(orig);
                        }
                    }
                }
            }));

            return(tcs.Task);
        }