Go to the first, previous, next, last section, table of contents.


Low-level concurrency/multithreading primitives

Author(s): Manuel Carro.

Version: 1.11#222 (2004/5/24, 13:8:7 CEST)

Version of last change: 1.7#138 (2001/11/8, 19:50:32 CET)

This module provides basic mechanisms for using concurrency and implementing multi-goal applications. It provides a means for arbitrary goals to be specified to be run in a separate stack set; in that case, they are assigned a goal identifier with which further accesses (e.g., asking for more solutions) to the goal can be made. Additionally, in some architectures, these goals can be assigned an O.S. thread, separate from the one which made the initial call, thus providing concurrency and, in multiprocessors, parallelism capabilities.

As for now, the memory space of the threads (c.f., stack sets) is separate in the sense that goals are copied to the new stack set, and bindings of variables are not seen among stack sets which allows forward and backward execution to proceed independently in each stack set, at the cost of the initial goal copy. However, the program space (including, specially, the concurrent predicates) are shared and seen by all the goals and threads, and should be used as the primary means of communication and synchronization. Higer level libraries can be built using these basic blocks.

Additionally, a small set of lock primitives are provided. Locks are associated with atom names. Whereas the concurrent database facilities are enough to implement locks, semaphores, messages, etc., the predicates implementing atom-based locks are faster than the ones accessing the concurrent database (but they are less powerful).

Usage and interface (concurrency)

Documentation on exports (concurrency)

PREDICATE: eng_call/4:

Meta-predicate with arguments: eng_call(goal,?,?,?).

Usage: eng_call(Goal, EngineCreation, ThreadCreation, GoalId)

PREDICATE: eng_call/3:

Meta-predicate with arguments: eng_call(goal,?,?).

Usage: eng_call(Goal, EngineCreation, ThreadCreation)

PREDICATE: eng_backtrack/2:

Usage: eng_backtrack(GoalId, ThreadCreation)

PREDICATE: eng_cut/1:

Usage: eng_cut(GoalId)

PREDICATE: eng_release/1:

Usage: eng_release(GoalId)

PREDICATE: eng_wait/1:

Usage: eng_wait(GoalId)

PREDICATE: eng_kill/1:

Usage: eng_kill(GoalId)

PREDICATE: eng_killothers/0:

Usage:

PREDICATE: eng_self/1:

Usage: eng_self(GoalId)

PREDICATE: goal_id/1:

Usage: goal_id(GoalId)

PREDICATE: eng_goal_id/1:

Usage: eng_goal_id(GoalId)

PREDICATE: eng_status/0:

Usage:

PREDICATE: lock_atom/1:

Usage: lock_atom(Atom)

PREDICATE: unlock_atom/1:

Usage: unlock_atom(Atom)

PREDICATE: atom_lock_state/2:

Usage 1: atom_lock_state(Atom, Value)

Usage 2: atom_lock_state(Atom, Value)

PREDICATE: concurrent/1:

concurrent F/A

The predicate named F with arity A is made concurrent in the current module at runtime (useful for predicate names generated on-the-fly). This difficults a better compile-time analysis, but in turn offers more flexibility to applications. It is also faster for some applications: if several agents have to share data in a stuctured fashion (e.g., the generator knows and wants to restrict the data generated to a set of other threads), a possibility is to use the same concurrent fact and emply a field within the fact to distinguish the receiver/sender. This can cause many threads to access and wait on the same fact, which in turns can create contention problems. It is much better to create a new concurrent fact and to use that new name as a channel to communicate the different threads. concurrent/1 can either be given a predicate spec in the form Name/Arity, with Name and Arity bound, or to give a value only to Arity, and let the system choose a new, unused Name for the fact.

Usage: concurrent Spec

Known bugs and planned improvements (concurrency)


Go to the first, previous, next, last section, table of contents.