In terms of programming, when wanting to transform a single-threaded program into multi-threaded one has to get into a different mindset.
In terms of Prolog (Tabard and most Prolog systems that support multi-threading), that means replacing:
- 1) predicates into thread_send_message()’s
- 2) unbound variables into thread_get_message()’s
Example: Consider the Prolog goal in single-thread mode:
% pred(+A, +B, -C)
pred([1,2], [[2,2], [3,2]], X).
And now in multi-threading mode, on the master thread side:
thread_send_message(worker_queue, pred([1,2], [[2,2], [3,2]])),
thread_get_message(master_queue, X).
And in the worker thread side:
thread_get_message(worker_queue, Y),
(do processing)
thread_send_message(master, Result).
And now for a real example (tested on SWI-Prolog):
%
% multiple threads wait on a single queue and pick up the first
% goal to execute. This example provides no means to tell when all
% work is done. This must be realised using additional
% synchronisation.
%
trick(a(gnu), b(software)). %answer is message is a(gnu)
trick(_, c(is)). %answer if not
% create_workers(+Id, +N)
%
% Create a pool with given Id and number of workers
% A set of workers wait on a single queue
%
create_workers(WorkerQueue, MasterQueue, N):-
message_queue_create(WorkerQueue),
message_queue_create(MasterQueue),
forall(between(1, N, _),
thread_create(do_work(WorkerQueue, MasterQueue), _, [])).
%
% Workers
%
do_work(WorkerQueue, MasterQueue):-
repeat,
thread_get_message(WorkerQueue, Goal),
% do processing
!, trick(Goal, X),
thread_send_message(MasterQueue, X),
fail.
% Master
%
% work(+Id, +Goal)
%
% Post work to be done by the pool
work(WorkerQueue, MasterQueue, Goal):-
thread_send_message(WorkerQueue, Goal),
thread_get_message(MasterQueue, Result),
write(Result).