Who should catch the exception? Detached threads are really that: they are no longer supervised by anything. They die without leaving a trace as they have no place to report to. Mostly for debugging it prints exceptions or failure. If you do not want that, wrap the goal in catch/3 and send the exception somewhere. Note that applications can use prolog_listen/3 to keep overall track of created and terminated threads. Not sure how useful that is.
P.s. Possibly you think a dying thread should cause an asynchronous exception in the thread that created the thread? Note that in the POSIX thread world the creator is irrelevant and may decide to terminate before its children (that notion doesn’t exist anyway).
You can’t catch abort. Well, you can but the recovery handler is wrapped in call_cleanup(Handler, abort). To avoid this don’t use detached. That is also correct as apparently you do want to keep control over the thread. Now, you kill a thread forcefully by injecting an abort and use thread_join/2.
It doesn’t catch any exception, the following also prints the warning also.
?- thread_create(catch(sleep(0.5),_,true),T,[detached(true)]),
thread_signal(T,throw(done)). % notice the exception is not abort
T = <thread>(4,0x562b28a93680).
Warning: [Thread 4] Thread running "'$thread_init'" died on exception: Unknown message: done
Yes, I can do that too.
The use case is rather uncommon I guess, it is just a dummy thread used in one test, and in another test I wanted to make sure the thread was dead because the alias is reused in the second test and I just wanted to get rid of the message.
I will just not use detached on the first test and join the thread.
Nonetheless, thread_create/3 docs mention that one can use catch/3 to catch the exception in a detached thread (this is why I kept the detached thread):
If a detached thread dies due to failure or exception of the initial goal, the thread prints a message using print_message/2. If such termination is considered normal, the code must be wrapped using ignore/1 and/or catch/3 to ensure successful completion.
The problem is that your signal arrives before the catch/3 is started, i.e., it arrives during the thread initialization. Try this:
?- thread_create(catch(sleep(0.5),_,true),T,[detached(true)]),
sleep(0.1), % give some time to get into the catch/3
thread_signal(T,throw(done)).
T = <thread>(3,0x559bf5930320).
Of course, using sleep/1 to get the timing right is bad. Normally you’d send a message to your creator when you are ready and the creator needs to wait for that.
As for tests, all SWI-Prolog tests that create threads join these before the test completes.
In this case I just need a dummy thread to take up the alias name during the test, so I’ll just abort it and join it. The timing is not really important because I’ll abort the dummy thread when the test has completed.