This built-in can be used in multithreaded or parallel programs to implement mutual exclusion between concurrently running engines. Goals that are protected via with_mutex/2 on the same Mutex object can only be executed by one engine at a time.
Note that in a side effect free program there is no need ever to worry about mutual exclusion. Also, individual calls to built-ins performing side-effects (stream I/O operations, operations on nonlogical storage, etc) do not need extra protection, because they internally lock the object they operate on. The purpose of with_mutex/2 is therefore to make a sequence of multiple side-effects atomic, when this is necessary to maintain consistency of shared data structures.
The following object handles can be used as Mutex:
Mutexes are recursive, i.e. nested calls to with_mutex/2 within a thread are allowed. Mutexes are automatically unlocked when the control flow leaves the with_mutex/2 predicate, whether via success, failure, throw/1 or exit/1.
The standard precautions for working with mutexes apply: they should be held as briefly as possible to avoid unnecessary blocking of other threads. Also, nesting of (explicit or implicit) mutexes can lead to deadlocks.
% make sure a list is printed in one chunk % use the stream's own mutex for exclusion atomic_write_list(Stream, List) :- with_mutex(Stream, write_list(Stream, List)). write_list(Stream, []) :- nl(Stream). write_list(Stream, [X|Xs]) :- writeln(Stream, X), write_list(Stream, Xs).