Dear All,

(sorry for the long post)

I have been experimenting a bit with GCD in MacRuby 0.5 beta.

I have managed to get some code working as I would expect it to work, and I am wondering if a few of you could provide a sanity check that everything i am doing is above board and not the result of unspecified behaviour.

My main concern is that when running a set of tasks and collecting the results that the collecting itself is not thread safe (in this case the << operator). And if it is not thread safe - then what is the best way to collect results from dispatched tasks.

But so far it seems to work magically well.

Before I put the code down - here are some initial discoveries (which may have been obvious to everyone else).

1. When running tests you need wait until the threads are finished - otherwise the main loop will finish before the output comes back from other threads. I did that with a sleep, but also experimented with looping until an array is filled.

2. Scope: Given one of the global system queues :               
gcdq = Dispatch::Queue.concurrent(:default)

and looping over a number of dispatches:
5.times do |index|
        gcdq.dispatch {puts index}
end
the task dispatched will hold the last value of index - it will not capture the changing value of index - I assume that the task has a pointer directly to the index variable. (an article by Bill Bumgarner http://www.friday.com/bbum/2009/08/29/blocks-tips-tricks/ pointed out something similar in objC - but had a different way of solving this)

So to capture that changing index, I created a Proc then turned it back to a block, eg:
5.times do |index|
        task = Proc.new {puts index}
        gcdq.dispatch &task
end

3. You will notice that in the code below in check = a.run-disp2 that the array is returned - I assume empty - and is gradually filled by the tasks.

class A
  def run_disp(an_array)
    gcdq = Dispatch::Queue.concurrent(:default)
    ["f","g","h","i", "j"].each_with_index do |val, index|
       task = Proc.new {an_array  << do_something(val, index)}
       gcdq.dispatch &task
      puts "Loaded #{index}"
    end
  end

  def run_disp2
    an_array = []
    gcdq = Dispatch::Queue.concurrent(:default)
    ["f","g","h","i", "j"].each_with_index do |val, index|
       task = Proc.new {an_array  << do_something(val, index)}
       gcdq.dispatch &task
      puts "Loaded #{index}"
    end
    an_array
  end

  def do_something(val, index)
    #staggered sleeps so as to prove that various tasks finish first
    result = val * (index + 1)
    case index
    when 0, 1
      sleep 2
    when 2
      sleep 1
    else
      sleep 0
    end
    puts "yeah baby! #{index}"
    result
  end
end

a = A.new
#pass array to be filled
an_array = []
a.run_disp(an_array)
sleep 10
puts "passed array: #{an_array.join(", ")}"

check = a.run_disp2
sleep 10
puts "returned array: #{check.join(", ")}"

#results:
#     Loaded 0
#     Loaded 1
#     Loaded 2
#     Loaded 3
#     Loaded 4
#     yeah baby! 4yeah baby! 3
#
#     yeah baby! 2
#     yeah baby! 1
#     yeah baby! 0
#     passed array: iiii, jjjjj, hhh, gg, f
#     Loaded 0
#     Loaded 1
#     Loaded 2
#     Loaded 3
#     Loaded 4
#     yeah baby! 3
#     yeah baby! 4
#     yeah baby! 2
#     yeah baby! 0
#     yeah baby! 1
#     returned array: iiii, jjjjj, hhh, f, gg

#assume puts is not transactional.


thanks in advance for any comments / corrections,
John
_______________________________________________
MacRuby-devel mailing list
MacRuby-devel@lists.macosforge.org
http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel

Reply via email to