/// <summary> /// Sends a value over the channel. If no other <see cref="MicroThread"/> is waiting for data, the sender will be blocked. /// If someone was waiting for data, which of the sender or receiver continues next depends on <see cref="Preference"/>. /// </summary> /// <param name="data">The data.</param> /// <returns>Awaitable data.</returns> public ChannelMicroThreadAwaiter <T> Set <T>(T data) { Type key = typeof(T); if (!receivers.ContainsKey(key) || (receivers.ContainsKey(key) && receivers[key].Count == 0)) { // Nobody receiving, let's wait until something comes up var microThread = MicroThread.Current; var waitingMicroThread = ChannelMicroThreadAwaiter <T> .New(microThread); waitingMicroThread.Result = data; if (senders.ContainsKey(key)) { senders[key].Enqueue(waitingMicroThread); return(waitingMicroThread); } else { ConcurrentQueue <ChannelMicroThreadAwaiterBase> tmp = new ConcurrentQueue <ChannelMicroThreadAwaiterBase>(); senders.AddOrUpdate(key, tmp, (a, b) => tmp); senders[key].Enqueue(waitingMicroThread); return(waitingMicroThread); } } ChannelMicroThreadAwaiterBase receiverbase; if (receivers[key].TryDequeue(out receiverbase)) { var receiver = receiverbase as ChannelMicroThreadAwaiter <T>; receiver.Result = data; if (Preference == ChannelPreference.PreferSender) { receiver.MicroThread.ScheduleContinuation(ScheduleMode.Last, receiver.Continuation); } else if (Preference == ChannelPreference.PreferReceiver) { receiver.MicroThread.ScheduleContinuation(ScheduleMode.First, receiver.Continuation); // throw new NotImplementedException(); //await Scheduler.Yield(); } receiver.IsCompleted = true; return(receiver); } else { return(null); } }
/// <summary> /// Receives a value over the channel. If no other <see cref="MicroThread"/> is sending data, the receiver will be blocked. /// If someone was sending data, which of the sender or receiver continues next depends on <see cref="Preference"/>. /// </summary> /// <returns>Awaitable data.</returns> public ChannelMicroThreadAwaiter <T> Get <T>() { Type key = typeof(T); if (!senders.ContainsKey(key) || (senders.ContainsKey(key) && senders[key].Count == 0)) { var microThread = MicroThread.Current; if (microThread == null) { throw new Exception("Cannot receive out of micro-thread context."); } var waitingMicroThread = ChannelMicroThreadAwaiter <T> .New(microThread); if (receivers.ContainsKey(key)) { receivers[key].Enqueue(waitingMicroThread); return(waitingMicroThread); } else { ConcurrentQueue <ChannelMicroThreadAwaiterBase> tmp = new ConcurrentQueue <ChannelMicroThreadAwaiterBase>(); receivers.AddOrUpdate(key, tmp, (a, b) => tmp); receivers[key].Enqueue(waitingMicroThread); return(waitingMicroThread); } } ChannelMicroThreadAwaiterBase sender; if (senders[key].TryDequeue(out sender)) { if (Preference == ChannelPreference.PreferReceiver) { sender.MicroThread.ScheduleContinuation(ScheduleMode.Last, sender.Continuation); } else if (Preference == ChannelPreference.PreferSender) { sender.MicroThread.ScheduleContinuation(ScheduleMode.First, sender.Continuation); } sender.IsCompleted = true; return(sender as ChannelMicroThreadAwaiter <T>); } else { return(null); } }