[m-users.] Calling exit(3) from a foreign predicate

Volker Wysk post at volker-wysk.de
Fri Jan 26 01:24:51 AEDT 2024


Am Donnerstag, dem 25.01.2024 um 07:53 +0000 schrieb Sean Charles
(emacstheviking):
> What a module accessible flag for global control then I guess?
> 
> :- module foo.
> 
> :- pred is_exit_requested.
> 
> :- implementation.
> 
> :- mutable (stop_flag, bool, no, ground, [...whats your app needs...]).
> 
> :- pragma promise_pure(stop_threads/0). 
> :- pred stop_threads :-
>     impure set_stop_flag(yes).
> 
> 
> :- pragma promise_pure(iis_exit_requested/0). 
> :- pred is_exit_requested is semidet.
> is_exit_requested :-
>     semipure get_stop_flag(yes).
> 
> 
> then inside your threads you can just called   foo.is_exit_requested ?
> This is off the top of my head, so I have probably made a few m istakes,
> it's early and I've not had my porridge yet, those are my excuses!
> 
> That's kind of what I was hinting at nefpre; external control, but I
> assumed you were passing two-way control structures but if the threads
> have no ears then thisd might be the solution / a solution?
> 
> Good luck VOlker, you always figure out!

Thanks for your consideration. But the infrastructure for shutting down the
threads is already in place (except for one piece).

It works like this: There's a master thread (the main program), which spawns
a feeder thread and a number of worker threads. 

The feeder is connected to the workers and to master by a channel each. It
feeds work items (paths to files) to the workers. Those do something with
it. They bring the database up to date with respect to the path. They also
(re)calculate hashes of the files, when needed. The workers send the work
results (hashes) to master, which does something with it. 

The feeder also sends messages to master about the succession in which the
files occur. And when all work has been feeded, the feeder sends an "end"
message to all workers. This message causes the worker to send an "end"
message to master, on his part, and to leave the predicate which it has been
started with. Meaning the worker terminates.

Master does something with the received work results. It depends on which
operation has been chosen. Such as "print the hashes of the files".

When there happens a database error, the whole process, meaning all threads,
should be terminated. It can occur in one worker, or occur in all workers
(such as authentication failure when establishing the database connection). 

Now, in order terminate the process, I can go the easy way and just call
exit(3). The downside is, that the Mercury shutdown isn't carried out
(except for what exit() does).

The other way would be to cause the threads (workers and feeder) to
terminate themselves. The feeder would need to be instructed to stop feeding
and terminate. It should send "end" messages to all workers, and terminate
itself afters. Then master needs to collect all messages (work
results/errors), which are still pending. And it needs to collect and count
the "end" messages from the workers to master, so it knows when all workers
have terminated.

Informing the feeder to stop feeding, could be done with an mvar
(thread.mvar module).

The downside of this is, that it's more complicated than the easy way. (It's
hard to debug inter-thread-communication). And it would mean waiting until
all workers are done with their work. That can take a long time, when a
worker is calculating the hash of a large file...

So, which way should I take?  I guess it depends on how bad it is to
terminate the process the hard way by calling exit(3) and not calling
mercury_runtime_terminate().

I hope I haven't bored you.

Cheers,
Volker


More information about the users mailing list