Jorge Marques Pelizzoni wrote:
That's very important indeed. I just didn't mention that because it really
does not apply to your case. Anyway, Raphael's advice is always worth
taking :o)
You're right. I focused too much on the message title. In fact your
problem is not really about exceptions...
%% 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
You see, here you already have a race condition. And this innocent looking
procedure might well produce (unwanted) failure. Imagine that there are
two threads that have just finished {F X} with True, for different Xs. One
thread tests {IsFree Result} and is preempted just after that; while the
other is activated and also gets True in {IsFree Result}. Mess is likely
to ensue.
Correct! IsFree is an evil function: it looks nice, but it's not!
The correct way to write ConcurrentFind is use some mutual exclusion
device when accessing Result (as in my Spawner example). Here I'll use a
more explicit such device (there I used a cell to perform mutual
exclusion):
(...)
declare
proc {ConcurrentFind2 Xs F ?Result}
L = {NewLock}
Threads = {Map Xs proc {$ X T}
thread
T = {Thread.this}
if {F X} then
lock L then
if {IsFree Result} then Result = X end
end
end
{Wait _}
end
end}
in
{Wait Result}
{ForAll Threads Thread.terminate}
end
I like the trick to never let a thread terminate normally. But I don't
like locks... Here is an alternative solution, that uses a port instead
of a lock. The threads do not bind Result themselves, instead they send
the value on the port if it the test is positive. The first value sent
on the port is taken as the ConcurrentFind's result. No need for
explicit mutual exclusion, and no need for IsFree.
proc {ConcurrentFind3 Xs F ?Result}
S P={NewPort S}
Threads = {Map Xs proc {$ X T}
thread
T={Thread.this}
if {F X} then {Send P X} end
{Wait _}
end
end}
in
Result = S.1 % wait for first value sent
{ForAll Threads Thread.terminate}
end
Cheers,
raph
_________________________________________________________________________________
mozart-users mailing list
[email protected]
http://www.mozart-oz.org/mailman/listinfo/mozart-users