7 Channels 7.1 Channels Channels are FIFO queues that threads can use to coordinate their activities. 7.1-1 CreateChannel CreateChannel( [capacity] )  function 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. 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  gap> ch1:=CreateChannel();  gap> ch2:=CreateChannel(5);   7.1-2 SendChannel SendChannel( channel, obj )  function SendChannel accepts two arguments, a channel object returned by CreateChannel (7.1-1), and an arbitrary GAP object. It stores obj in channel. If channel has a finite capacity and is currently full, then SendChannel will block until at least one element has been removed from the channel, e.g. using ReceiveChannel (7.1-6). SendChannel performs automatic region migration for thread-local objects. If obj is thread-local for the current thread, it will be migrated (along with all subobjects contained in the same region) to the receiving thread's thread-local data space. In between sending and receiving, obj cannot be accessed by either thread. This example demonstrates sending messages across a channel.  Example  gap> ch1 := CreateChannel();; gap> SendChannel(ch1,1); gap> ch1;  gap> ReceiveChannel(ch1); 1 gap> ch1;   Sleep in the following example is used to demonstrate blocking.  Example  gap> ch2 := CreateChannel(5);; gap> ch3 := CreateChannel();; gap> for i in [1..5] do SendChannel(ch2,i); od; gap> ch2;  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);  7.1-3 TransmitChannel TransmitChannel( channel, obj )  function TransmitChannel is identical to SendChannel (7.1-2), except that it does not perform automatic region migration of thread-local objects.  Example  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  7.1-4 TrySendChannel TrySendChannel( channel, obj )  function TrySendChannel is identical to SendChannel (7.1-2), except that it returns if the channel is full instead of blocking. It returns true if the send was successful and false otherwise.  Example  gap> ch := CreateChannel(1);; gap> TrySendChannel(ch, 99); true gap> TrySendChannel(ch, 99); false  7.1-5 TryTransmitChannel TryTransmitChannel( channel, obj )  function TryTransmitChannel is identical to TrySendChannel (7.1-4), except that it does not perform automatic region migration of thread-local objects. 7.1-6 ReceiveChannel ReceiveChannel( channel )  function ReceiveChannel is used to retrieve elements from a channel. If channel is empty, the call will block until an element has been added to the channel via SendChannel (7.1-2) or a similar primitive. See SendChannel (7.1-2) for an example. 7.1-7 TryReceiveChannel TryReceiveChannel( channel, default )  function TryReceiveChannel, like ReceiveChannel (7.1-6), attempts to retrieve an object from channel. If it does not succeed, however, it will return default rather than blocking.  Example  gap> ch := CreateChannel();; gap> SendChannel(ch, 99); gap> TryReceiveChannel(ch, fail); 99 gap> TryReceiveChannel(ch, fail); fail  7.1-8 MultiSendChannel MultiSendChannel( channel, list )  function MultiSendChannel allows the sending of all the objects contained in the list list to channel 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. The operation is designed to be more efficient than sending all elements individually via SendChannel (7.1-2) by minimizing potentially expensive concurrency operations. See MultiReceiveChannel (7.1-10) for an example. 7.1-9 TryMultiSendChannel TryMultiSendChannel( channel, list )  function TryMultiSendChannel operates like MultiSendChannel (7.1-8), 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 channel does not have finite capacity, TryMultiSendChannel will always send all elements in the list. 7.1-10 MultiReceiveChannel MultiReceiveChannel( channel, amount )  function MultiReceiveChannel is the receiving counterpart to MultiSendChannel (7.1-8).It will try to receive up to amount objects from channel. If the channel contains less than amount objects, it will return rather than blocking. The function returns a list of all the objects received.  Example  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); [ ]  7.1-11 ReceiveAnyChannel ReceiveAnyChannel( channel_1, ..., channel_n )  function ReceiveAnyChannel( channel_list )  function ReceiveAnyChannel is a multiplexing variant ofReceiveChannel (7.1-6). 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  gap> ch1 := CreateChannel();; gap> ch2 := CreateChannel();; gap> SendChannel(ch2, [1, 2, 3]);; gap> ReceiveAnyChannel(ch1, ch2); [ 1, 2, 3 ]  7.1-12 ReceiveAnyChannelWithIndex ReceiveAnyChannelWithIndex( channel_1, ..., channel_n )  function ReceiveAnyChannelWithIndex( channel_list )  function ReceiveAnyChannelWithIndex works like ReceiveAnyChannel (7.1-11), 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  gap> ch1 := CreateChannel();; gap> ch2 := CreateChannel();; gap> SendChannel(ch2, [1, 2, 3]);; gap> ReceiveAnyChannelWithIndex(ch1, ch2); [ [ 1, 2, 3 ], 2 ]  7.1-13 TallyChannel TallyChannel( channel )  function 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  gap> ch := CreateChannel();; gap> SendChannel(ch, 2); gap> SendChannel(ch, 3); gap> SendChannel(ch, 5); gap> TallyChannel(ch); 3  7.1-14 InspectChannel InspectChannel( channel )  function 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  gap> ch := CreateChannel();; gap> SendChannel(ch, 2); gap> SendChannel(ch, 3); gap> SendChannel(ch, 5); gap> InspectChannel(ch); [ 2, 3, 5 ]  This function is primarly intended for debugging purposes.