/// <summary>Returns an item, blocking if not ready</summary> /// <remarks>returns <see cref="Maybe{T}.None()"/> without blocking if the channel is closed</remarks> public Maybe <T> Recv() { Waiter <T> r; lock (sync) { if (!items.Empty) { var value = items.Dequeue(); Debug.Print("Thread {0}, {1} Recv, removed item from itemq", Thread.CurrentThread.ManagedThreadId, GetType()); MoveSendQToItemQ(); return(Maybe <T> .Some(value)); } Waiter <T> s = senders.Dequeue(); if (s != null) { Debug.Print("Thread {0}, {1} Recv, waking sender", Thread.CurrentThread.ManagedThreadId, GetType()); var mv = s.Value; s.Wakeup(); return(mv); } if (closed) { Debug.Print("Thread {0}, {1} Recv, Channel is closed", Thread.CurrentThread.ManagedThreadId, GetType()); return(Maybe <T> .None()); } r = WaiterPool <T> .Get(); receivers.Enqueue(r); } // wait for a sender to signal it has sent Debug.Print("Thread {0}, {1} Recv, waiting", Thread.CurrentThread.ManagedThreadId, GetType()); r.WaitOne(); Debug.Print("Thread {0}, {1} Recv, woke up", Thread.CurrentThread.ManagedThreadId, GetType()); var v = r.Value; WaiterPool <T> .Put(r); return(v); }
/// <summary>Send a value, adds it to the item queue or blocks until the queue is no longer full</summary> public void Send(T v) { Waiter <T> s; lock (sync) { if (closed) { throw new ClosedChannelException("You cannot send on a closed Channel"); } if (items.Empty) { Waiter <T> wr = receivers.Dequeue(); if (wr != null) { wr.Value = Maybe <T> .Some(v); Debug.Print("Thread {0}, {1} Send({2}), SetItem succeeded", Thread.CurrentThread.ManagedThreadId, GetType(), wr.Value); wr.Wakeup(); return; } } if (!items.Full) { Debug.Print("Thread {0}, {1} Send({2}), spare capacity, adding to itemq", Thread.CurrentThread.ManagedThreadId, GetType(), v); items.Enqueue(v); return; } // at capacity, queue our waiter until some capacity is freed up by a recv s = WaiterPool <T> .Get(v); senders.Enqueue(s); } // wait for the receiver to wake us up Debug.Print("Thread {0}, {1} Send({2}), waiting ", Thread.CurrentThread.ManagedThreadId, GetType(), v); s.WaitOne(); Debug.Print("Thread {0}, {1} Send({2}), woke up after waiting ", Thread.CurrentThread.ManagedThreadId, GetType(), v); WaiterPool <T> .Put(s); }
void IChannel.ReleaseWaiter(IWaiter h) { WaiterPool <T> .Put((Waiter <T>) h); }
/// <summary>Gets a waiter for use in RecvSelect</summary> IWaiter IChannel.GetWaiter() { return(WaiterPool <T> .Get()); }