Dear Jorge, dear Raphael,

again, thank you both for your informative reply.

Best
Torsten

On Mar 14, 2008, at 9:55 PM, Raphael Collet wrote:

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 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

Reply via email to