Dear Jorge, dear Raphael,
thank you both for your kind reply. In particular, I found it
important to learn about the use of Value.failed! Still, I probably
should have told you from the beginning what I am actually after :)
The following procedure ConcurrentFind does already what I want to
do. I want a higher-order function which returns an element from a
given list Xs for which a given Boolean function F returns true.
However, this function should not completely block on undetermined
list elements if some later list element would already be a hit.
Brief background info: I want to use ConcurrentFind in CSPs quasi as
some form of a selection constraint for arbitrary values, more
specifically for objects containing variables. ConcurrentFind (and
its brother ConcurrentFilter) is used to delay constraint
applications until enough information became available during the
search process to decide to which objects/variables the constraints
in question are applied. I use this as an alternative to FD.impl and
friends. For example, my function F may internally call some reified
constraint and transform its result into a Boolean (e.g.,
{MyConstraint} == 1). Some constraints are then applied to the object
returned by ConcurrentFind.
/** %% Find some element in Xs for which F returns true. The Result
is not necessarily the first 'matching' element in Xs, but
ConcurrentFind returns a result as soon as enough information is
available to decide for any element.
%% Inefficient version: after ConcurrentFind already found an
element, concurrent threads may still continue running.
%% */
proc {ConcurrentFind Xs F ?Result}
{ForAll Xs proc {$ X}
thread
%% blocks until X is sufficiently determined
if {F X} andthen {IsFree Result}
then Result = X
end
end
end}
end
Here is an example which demonstrates its use. Note that the second
element of Xs is never determined and still ConcurrentFind returns a
matching value.
declare
Xs = [1 _ 2 _ 3 _ 2]
Y = {ConcurrentFind Xs fun {$ X} X > 3 end}
{Browse Y}
%% Y will be either 5 or 6 (whoever comes first)
thread {Nth Xs 4} = 5 end
thread {Nth Xs 6} = 6 end
Now, the issue with this version of ConcurrentFind is that there
still may be 'pending' threads after ConcurrentFind returned. If used
as a 'selection constraint' as sketched above, many threads may still
be pending because many values in Xs may not be determined enough for
F to return anything. Can I somehow terminate those threads?
Here is a _not-working_ example demonstrating the idea, but this
version always throws an exception kernel(deadThread <SomeThread>).
What does this exception mean and is there a way to prevent it?
Jorge, I am sorry -- I tried to understand why this exception does
not happen in the example you gave, but I don't see why.
%% BUGGY: Causes exception: kernel(deadThread <SomeThread>)
proc {ConcurrentFind2 Xs F ?Result}
Threads = {Map Xs proc {$ X T}
thread
T = {Thread.this}
if {F X} andthen {IsFree Result}
then Result = X
end
end
end}
in
{Wait Result}
{ForAll Threads Thread.terminate}
end
Thank you very much!
Best
Torsten
On Mar 14, 2008, at 2:53 PM, Raphael Collet wrote:
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 mozart-
[EMAIL PROTECTED]
http://www.mozart-oz.org/mailman/listinfo/mozart-users
--
Torsten Anders
Interdisciplinary Centre for Computer Music Research
University of Plymouth
Office: +44-1752-233667
Private: +44-1752-558917
http://strasheela.sourceforge.net
http://www.torsten-anders.de
_________________________________________________________________________________
mozart-users mailing list
[email protected]
http://www.mozart-oz.org/mailman/listinfo/mozart-users