<Chapter Label="Channels">
  <Heading>Channels</Heading>

<Section Label="section:Channels">
  <Heading>Channels</Heading>

  Channels are FIFO queues that threads can use to coordinate their activities.

<ManSection>
    <Func Name="CreateChannel"
      Arg='[capacity]'/>

<Description>
<Ref Func="CreateChannel"/> returns a FIFO communication channel that can be used to exchange information between threads. Its
optional argument is a capacity (positive integer). If insufficient resources are available to create a channel, it
returns -1. If the capacity is not a positive integer, an error will be raised.
<P/>
If a capacity is not provided, by default the channel can hold an indefinite number of objects. Otherwise, attempts to
store objects in the channel beyond its capacity will block.

<Example><![CDATA[
gap> ch1:=CreateChannel();
<channel 0x460339c: 0 elements, 0 waiting>
gap> ch2:=CreateChannel(5);
<channel 0x460324c: 0/5 elements, 0 waiting>
]]></Example>
</Description>
</ManSection>

<ManSection>
    <Func Name="SendChannel"
      Arg='channel, obj'/>

<Description>
<Ref Func="SendChannel"/> accepts two arguments, a channel object returned by <Ref Func="CreateChannel"/>, and an arbitrary GAP
object. It stores <A>obj</A> in <A>channel</A>. If <A>channel</A> has a finite capacity and is currently full, then
<Ref Func="SendChannel"/> will block until at least one element has been removed from the channel, e.g. using <Ref
Func="ReceiveChannel"/>.
<P/>
<Ref Func="SendChannel"/> performs automatic region migration for thread-local objects. If <A>obj</A> is thread-local for the
current thread, it will be migrated (along with all subobjects contained in the same region) to the receiving
thread&#39;s thread-local data space. In between sending and receiving, <A>obj</A> cannot be accessed by either thread.
<P/>
This example demonstrates sending messages across a channel.

<Example><![CDATA[
gap> ch1 := CreateChannel();;
gap> SendChannel(ch1,1);
gap> ch1;
<channel 0x460339c: 1 elements, 0 waiting>
gap> ReceiveChannel(ch1);
1
gap> ch1;
<channel 0x460339c: 0 elements, 0 waiting>
]]></Example>

<C>Sleep</C> in the following example is used to demonstrate blocking.

<Example><![CDATA[
gap> ch2 := CreateChannel(5);;
gap> ch3 := CreateChannel();;
gap> for i in [1..5] do SendChannel(ch2,i); od;
gap> ch2;
<channel 0x460324c: 5/5 elements, 0 waiting>
gap> t:=CreateThread(
> function()
> local x;
> Sleep(10);
> x:=ReceiveChannel(ch2);
> Sleep(10);
> SendChannel(ch3,x);
> Print("Thread finished\n");
> end);;
> SendChannel(ch2,3); # this blocks until the thread reads from ch2
gap> ReceiveChannel(ch3); # the thread is blocked until we read from ch3
1
Thread finished
gap> WaitThread(t);
]]></Example>
</Description>
</ManSection>


<ManSection>
    <Func Name="TransmitChannel"
      Arg='channel, obj'/>

<Description>
<Ref Func="TransmitChannel"/> is identical to <Ref Func="SendChannel"/>,
except that it does not perform automatic region migration of
thread-local objects.

<Example><![CDATA[
gap> ch := CreateChannel(5);;
gap> l := [ 1, 2, 3];;
gap> original_region := RegionOf(l);;
gap> SendChannel(ch, l);
gap> WaitThread(CreateThread(function()
>      local ob; ob := ReceiveChannel(ch);
>      Display(RegionOf(ob) = original_region);
>    end));
false
gap> l := [ 1, 2, 3];;
gap> original_region := RegionOf(l);;
gap> TransmitChannel(ch, l);
gap> WaitThread(CreateThread(function()
>      local ob; ob := ReceiveChannel(ch);
>      Display(RegionOf(ob) = original_region);
>    end));
true
]]></Example>
</Description>
</ManSection>


<ManSection>
    <Func Name="TrySendChannel"
      Arg='channel, obj'/>

<Description>
<Ref Func="TrySendChannel"/> is identical to <Ref Func="SendChannel"/>,
except that it returns if the channel is full instead of
blocking. It returns true if the send was successful and false otherwise.

<Example><![CDATA[
gap> ch := CreateChannel(1);;
gap> TrySendChannel(ch, 99);
true
gap> TrySendChannel(ch, 99);
false
]]></Example>
</Description>
</ManSection>


<ManSection>
    <Func Name="TryTransmitChannel"
      Arg='channel, obj'/>

<Description>
<Ref Func="TryTransmitChannel"/> is identical to <Ref Func="TrySendChannel"/>,
except that it does not perform automatic region migration of thread-local objects.
</Description>
</ManSection>


<ManSection>
    <Func Name="ReceiveChannel"
      Arg='channel'/>

<Description>
<Ref Func="ReceiveChannel"/> is used to retrieve elements from a channel.
If <A>channel</A> is empty, the call will block until an element has been
added to the channel via <Ref Func="SendChannel"/> or a similar primitive.
<P/>
See <Ref Func="SendChannel"/> for an example.
</Description>
</ManSection>


<ManSection>
    <Func Name="TryReceiveChannel"
      Arg='channel, default'/>

<Description>
<Ref Func="TryReceiveChannel"/>, like <Ref Func="ReceiveChannel"/>,
attempts to retrieve an object from <A>channel</A>. If it does not
succeed, however, it will return <A>default</A> rather than blocking.

<Example><![CDATA[
gap> ch := CreateChannel();;
gap> SendChannel(ch, 99);
gap> TryReceiveChannel(ch, fail);
99
gap> TryReceiveChannel(ch, fail);
fail
]]></Example>
</Description>
</ManSection>


<ManSection>
    <Func Name="MultiSendChannel"
      Arg='channel, list'/>

<Description>
<Ref Func="MultiSendChannel"/> allows the sending of all the objects contained in the list <A>list</A> to <A>channel</A> as a
single operation. The list must be dense and is not modified by the call. The function will send elements starting at
index 1 until all elements have been sent. If a channel with finite capacity is full, then the operation will block
until all elements can be sent.
<P/>
The operation is designed to be more efficient than sending all elements individually via <Ref Func="SendChannel"/> by
minimizing potentially expensive concurrency operations.
<P/>
See <Ref Func="MultiReceiveChannel"/> for an example.
</Description>
</ManSection>


<ManSection>
    <Func Name="TryMultiSendChannel"
      Arg='channel, list'/>

<Description>
<Ref Func="TryMultiSendChannel"/> operates like <Ref Func="MultiSendChannel"/>,
except that it returns rather than blocking if it
cannot send any more elements if the channel is full.
It returns the number of elements it has sent. If <A>channel</A>
does not have finite capacity, <Ref Func="TryMultiSendChannel"/>
will always send all elements in the list.
</Description>
</ManSection>


<ManSection>
    <Func Name="MultiReceiveChannel"
      Arg='channel, amount'/>

<Description>
<Ref Func="MultiReceiveChannel"/> is the receiving counterpart to
<Ref Func="MultiSendChannel"/>.It will try to receive up to
<A>amount</A> objects from <A>channel</A>. If the channel contains less
than <A>amount</A> objects, it will return rather than blocking.
<P/>
The function returns a list of all the objects received.

<Example><![CDATA[
gap> ch:=CreateChannel();;
gap> MultiSendChannel(ch, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
gap> MultiReceiveChannel(ch,7);
[ 1, 2, 3, 4, 5, 6, 7 ]
gap> MultiReceiveChannel(ch,7);
[ 8, 9, 10 ]
gap> MultiReceiveChannel(ch,7);
[  ]
]]></Example>
</Description>
</ManSection>


<ManSection>
    <Func Name="ReceiveAnyChannel" Arg='channel_1, ..., channel_n'/>
    <Func Name="ReceiveAnyChannel" Arg='channel_list' Label="for a list of channels"/>
<Description>
<Ref Func="ReceiveAnyChannel"/> is a multiplexing variant of<Ref Func="ReceiveChannel"/>.
It blocks until at least one of the channels provided contains an object.
It will then retrieve that object from the channel and return it.

<Example><![CDATA[
gap> ch1 := CreateChannel();;
gap> ch2 := CreateChannel();;
gap> SendChannel(ch2, [1, 2, 3]);;
gap> ReceiveAnyChannel(ch1, ch2);
[ 1, 2, 3 ]
]]></Example>
</Description>
</ManSection>


<ManSection>
    <Func Name="ReceiveAnyChannelWithIndex" Arg='channel_1, ..., channel_n'/>
    <Func Name="ReceiveAnyChannelWithIndex" Arg='channel_list' Label="for a list of channels"/>
<Description>
<Ref Func="ReceiveAnyChannelWithIndex"/> works like <Ref Func="ReceiveAnyChannel"/>,
except that it returns a list with two elements, the first being the object
being received, the second being the number of the channel from which the
object has been retrieved.

<Example><![CDATA[
gap> ch1 := CreateChannel();;
gap> ch2 := CreateChannel();;
gap> SendChannel(ch2, [1, 2, 3]);;
gap> ReceiveAnyChannelWithIndex(ch1, ch2);
[ [ 1, 2, 3 ], 2 ]
]]></Example>
</Description>
</ManSection>


<ManSection>
    <Func Name="TallyChannel"
      Arg='channel'/>

<Description>
<Ref Func="TallyChannel"/> returns the number of objects that a channel contains. This number can increase or decrease, as data
is sent to or received from this channel. Send operations will only ever increase and receive operations will only ever
decrease this count. Thus, if there is only one thread receiving data from the channel, it can use the result as a lower
bound for the number of elements that will be available in the channel.

<Example><![CDATA[
gap> ch := CreateChannel();;
gap> SendChannel(ch, 2);
gap> SendChannel(ch, 3);
gap> SendChannel(ch, 5);
gap> TallyChannel(ch);
3
]]></Example>
</Description>
</ManSection>


<ManSection>
    <Func Name="InspectChannel"
      Arg='channel'/>

<Description>
<Ref Func="InspectChannel"/> returns a list of the objects that a channel contains. Note that objects that are not in the
shared, public, or read-only region will be temporarily stored in the so-called limbo region while in transit and will
be inaccessible through normal means until they have been received.

<Example><![CDATA[
gap> ch := CreateChannel();;
gap> SendChannel(ch, 2);
gap> SendChannel(ch, 3);
gap> SendChannel(ch, 5);
gap> InspectChannel(ch);
[ 2, 3, 5 ]
]]></Example>

This function is primarily intended for debugging purposes.
</Description>
</ManSection>
  </Section>
</Chapter>
