.. _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 ``out/1``
- **Read** tuples (without removing) using ``rd/1`` and ``rd_noblock/1``
- **Remove** tuples using ``in/1`` and ``in_noblock/1``

The blocking operations (``in/1``, ``rd/1``) suspend the process until a
matching tuple becomes available. The non-blocking variants
(``in_noblock/1``, ``rd_noblock/1``) fail immediately if no matching
tuple is found.

Tuples are matched using standard Prolog unification, allowing patterns
with variables.

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
-----

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

To start a Linda server that prints its address:

::

   | ?- linda::linda.
   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 (see API
  documentation)

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-operations-1:

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

- ``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)

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.
