Dear Torsten,

Oz exceptions are attached to their thread. All threads are independent and are not affected by exceptions in other threads. When you raise an exception in a thread, stack frames are popped until a "catch" frame is reached. If no "catch" frame is found, a default handler is called, and the thread terminates. The default handler at the toplevel just prints an error message. The default handler in a computation space makes the space fail.

In your case, you can probably spawn those threads in a computation space. If one of them fails, the space fails. All you have to do is to wait until the space succeeds (all threads are terminated normally) or fails (one of the threads crashed). The downside of that technique is that there is no way to catch the exception from outside the space.

Another technique is to use *failed values*. A failed value is a special value that encapsulates an exception, such that any attempt to "use" the value raises the exception. A failed value can be used to transmit an exception from a producer thread to its consumer thread(s). See "Value.failed" at the bottom of the page http://www.mozart-oz.org/documentation/base/node13.html#section.control.general

The following example shows how to execute a function Foo in a concurrent thread, such that exception can be caught in the threads using its result.

fun {Foo X Y Z}
   X*Y+Z           % may raise an exception if X is not a number, etc.
end

fun {BadConcurrentFoo X Y Z}
   thread {Foo X Y Z} end     % bad: the exception cannot be caught
end

fun {GoodConcurrentFoo X Y Z}
   thread
      try
         {Foo X Y Z}
      catch E then
         {Value.failed E}    % returns the exception in a failed value
      end
   end
end

try
   W={GoodConcurrentFoo 2 4 ouch}
in
   {Show success(W+5)}   % '+' raises exception if W is a failed value
catch E then
   {Show exception(E)}
end


You just have to make the thread you monitor return a result. The result can be the conventional 'unit' in case of a normal termination, and a failed value encapsulating any exception caught in the thread.

You will need a bit more stuff if you want to stop remaining threads, but at least you can catch the exception outside its original thread.

Cheers,
raph



Torsten Anders wrote:
Dear all,

Sorry if I missed some section in the Oz documentation concerning this issue.

How can I catch an exception raised in a (possibly nested) thread? Please consider the dummy example below, which is simply an edited version of an exception example in the tutorial. The difference is solely that Eval raises an exception from within a thread. As a consequence, it appears that the catch statement does never see this exception -- it is instead reported by the top-level.

proc {Eval E}
   thread
      case E
      of   plus(X Y) then {Browse X+Y}
      []   times(X Y) then {Browse X*Y}
      else raise illFormedExpression(E) end
      end
   end
end

try
   {ForAll [plus(5 10) times(6 11) min(7 10)] Eval}
catch
   illFormedExpression(X) then {Browse '** '#X#' **'}
end


As I said, this is only a dummy example. What I actually want to do is terminating a number of threads after one of them found a result, and I though that raising an exception containing the result would be a clean technique. BTW: I also tried terminating all my threads explicitly (see code below). Yet this resulted in another exception -- namely kernel(deadThread ...) ...) -- and so I was looking for alternative solutions..

{ForAll MyThreads Thread.terminate}

Thank you!

Best
Torsten

_________________________________________________________________________________ mozart-users mailing list [email protected]
http://www.mozart-oz.org/mailman/listinfo/mozart-users

_________________________________________________________________________________
mozart-users mailing list                               
[email protected]
http://www.mozart-oz.org/mailman/listinfo/mozart-users

Reply via email to