.. _library_linda:

``linda``
=========

Linda is a classic coordination model for process communication. This
library provides a Linda tuple-space implementation. Requires both
multi-threading and sockets support. It supports SWI-Prolog, Trealla
Prolog, and XVM.

The tuple-space is a shared blackboard where processes can:

- **Write** tuples using the ``out/1-2`` predicates
- **Read** tuples (without removing) using the ``rd/1-2`` and
  ``rd_noblock/1-2`` predicates
- **Remove** tuples using the ``in/1-2`` and ``in_noblock/1-2``
  predicates

The blocking predicates (``in/1-2``, ``rd/1-2``) suspend the process
until a matching tuple becomes available. The non-blocking variants
(``in_noblock/1-2``, ``rd_noblock/1-2``) fail immediately if no matching
tuple is found. There are also additional predicates for list
operations. Tuples are matched using unification.

API documentation
-----------------

Open the
`../../apis/library_index.html#linda <../../apis/library_index.html#linda>`__
link in a web browser.

Loading
-------

To load this library, load the ``loader.lgt`` file:

::

   | ?- logtalk_load(linda(loader)).

Testing
-------

To test this library predicates, load the ``tester.lgt`` file:

::

   | ?- logtalk_load(linda(tester)).

Usage
-----

The main library entities are the ``linda_server`` and ``linda_client``
categories. These categories provide a clean separation between server
and client code. For backward compatibility with the previous version of
this library, a ``linda`` object importing both categories is also
provided. The usage examples that follow use this object. An object
importing the ``linda_server`` category must use the ``threaded/0``
directive.

Starting a server
~~~~~~~~~~~~~~~~~

To start a Linda server that prints its address:

::

   | ?- linda::linda.
   % Server started at localhost:54321
   ...

To start a server with a callback when it starts:

::

   | ?- linda::linda([(Host:Port)-format('Server at ~w:~w~n', [Host, Port])]).

The server runs until all clients disconnect after a shutdown request.

Connecting a client
~~~~~~~~~~~~~~~~~~~

To connect to a server:

::

   | ?- linda::linda_client(localhost:54321).

Tuple operations
~~~~~~~~~~~~~~~~

Write a tuple:

::

   | ?- linda::out(message(hello, world)).

Read a tuple (blocking):

::

   | ?- linda::rd(message(X, Y)).
   X = hello,
   Y = world

Remove a tuple (blocking):

::

   | ?- linda::in(message(X, Y)).
   X = hello,
   Y = world

Non-blocking operations:

::

   | ?- linda::rd_noblock(message(X, Y)).
   no   % if no matching tuple exists

   | ?- linda::in_noblock(message(X, Y)).
   no   % if no matching tuple exists

Wait for one of several tuples:

::

   | ?- linda::in([task(1, X), task(2, X), done], Tuple).

Alternative syntax using ``in_list/2``:

::

   | ?- linda::in_list([task(1, X), task(2, X), done], Tuple).

Similarly for reading:

::

   | ?- linda::rd_list([status(ready), status(waiting)], Status).

Collect all matching tuples atomically (read without removing):

::

   | ?- linda::findall_rd_noblock(N, counter(N), Counters).

Collect and remove all matching tuples atomically:

::

   | ?- linda::findall_in_noblock(X, item(X), Items).

Disconnecting
~~~~~~~~~~~~~

Close the client connection:

::

   | ?- linda::close_client.

Request server shutdown (server stops accepting new connections):

::

   | ?- linda::shutdown_server, linda::close_client.

Timeout control
~~~~~~~~~~~~~~~

Set a timeout for blocking operations:

::

   | ?- linda::linda_timeout(Old, 5:0).  % 5 seconds timeout

Disable timeout (wait forever):

::

   | ?- linda::linda_timeout(_, off).

Examples
--------

Producer-Consumer
~~~~~~~~~~~~~~~~~

Producer (client 1):

::

   producer :-
       produce(X),
       linda::out(item(X)),
       producer.

Consumer (client 2):

::

   consumer :-
       linda::in(item(X)),
       consume(X),
       consumer.

Critical Region
~~~~~~~~~~~~~~~

::

   critical_section :-
       linda::in(mutex),  % acquire lock
       do_critical_work,
       linda::out(mutex). % release lock

Initialize the mutex:

::

   | ?- linda::out(mutex).

Synchronization
~~~~~~~~~~~~~~~

Wait for a signal:

::

   | ?- linda::in(ready).  % blocks until someone does out(ready)

Send a signal:

::

   | ?- linda::out(ready).

API Summary
-----------

Server predicates
~~~~~~~~~~~~~~~~~

- ``linda`` - Start server on automatic port
- ``linda(Options)`` - Start server with options

Client predicates
~~~~~~~~~~~~~~~~~

- ``linda_client(Address)`` - Connect to server at ``Host:Port``
- ``close_client`` - Close connection
- ``shutdown_server`` - Request server shutdown
- ``linda_timeout(Old, New)`` - Get/set timeout

Tuple predicates (single/default server)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

- ``out(Tuple)`` - Add tuple to space
- ``in(Tuple)`` - Remove matching tuple (blocking)
- ``in_noblock(Tuple)`` - Remove matching tuple (non-blocking)
- ``in(TupleList, Tuple)`` - Remove one of several tuples (blocking)
- ``in_list(TupleList, Tuple)`` - Remove one of several tuples
  (blocking)
- ``rd(Tuple)`` - Read matching tuple (blocking)
- ``rd_noblock(Tuple)`` - Read matching tuple (non-blocking)
- ``rd(TupleList, Tuple)`` - Read one of several tuples (blocking)
- ``rd_list(TupleList, Tuple)`` - Read one of several tuples (blocking)
- ``findall_rd_noblock(Template, Tuple, List)`` - Collect all matching
  tuples (atomic read)
- ``findall_in_noblock(Template, Tuple, List)`` - Collect and remove all
  matching tuples (atomic remove)

Tuple predicates (multiple servers)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Variants of the predicates above with an additional first argument for
the server address or the server alias (an atom; default is
``blackboard``).

Known issues
------------

Recent versions of macOS seem to disable the mapping of ``localhost`` to
``127.0.0.1``. This issue may prevent some functionality from working.
This can be fixed either by editing the ``/etc/hosts`` file or by using
``'127.0.0.1'`` as the host argument instead of ``localhost``.

See also
--------

- SICStus Prolog Linda documentation:
  https://sicstus.sics.se/sicstus/docs/latest4/html/sicstus.html/lib_002dlinda.html

- Original Linda papers:

  - Carreiro, N. & Gelernter, D. (1989). Linda in Context.
  - Carreiro, N. & Gelernter, D. (1989). How to Write Parallel Programs:
    A Guide to the Perplexed.
