[macruby-changes] [4339] MacRuby/trunk
source_changes at macosforge.org
source_changes at macosforge.org
Fri Jul 9 11:27:19 PDT 2010
Revision: 4339
http://trac.macosforge.org/projects/ruby/changeset/4339
Author: ernest.prabhakar at gmail.com
Date: 2010-07-09 11:27:19 -0700 (Fri, 09 Jul 2010)
Log Message:
-----------
Reformat dispatch README for better rdoc formatting
Modified Paths:
--------------
MacRuby/trunk/lib/dispatch/README.rdoc
MacRuby/trunk/sample-macruby/Scripts/gcd/dispatch_methods.rb
Modified: MacRuby/trunk/lib/dispatch/README.rdoc
===================================================================
--- MacRuby/trunk/lib/dispatch/README.rdoc 2010-07-09 01:37:55 UTC (rev 4338)
+++ MacRuby/trunk/lib/dispatch/README.rdoc 2010-07-09 18:27:19 UTC (rev 4339)
@@ -54,7 +54,7 @@
Wherever possible, you should instead attempt to figure out exactly _when_ and _why_ you need to know the result of asynchronous work. Then, call +value+ with a block to also perform _that_ work asynchronously once the value has been calculated -- all without blocking the main thread:
- job.value {|v| puts "value (async): #{v.to_int.to_s.size} => 1.0e+50" } # (eventually)
+ job.value {|v| puts "value (async): #{v} => 1.0e+50" } # (eventually)
=== Job#join: Job Completion
@@ -237,7 +237,7 @@
puts "p_map"
print (0..4).p_map(3) { |i| "#{10**i}\t" }.join
- puts "p_map(3) [sometimes fails!?!]"
+ puts "p_map(3)"
=== Enumerable#p_mapreduce
@@ -271,9 +271,9 @@
puts "find | p_find | p_find(3)"
- puts (0..4).find { |i| i == 5 } # => nil
- puts (0..4).p_find { |i| i == 5 } # => nil
- puts (0..4).p_find(3) { |i| i == 5 } # => nil
+ puts (0..4).find { |i| i == 5 }.nil? # => nil
+ puts (0..4).p_find { |i| i == 5 }.nil? # => nil
+ puts (0..4).p_find(3) { |i| i == 5 }.nil? # => nil
puts "#{(0..4).find { |i| i.odd? }} => 1"
puts "#{(0..4).p_find { |i| i.odd? }} => 1?"
@@ -281,14 +281,15 @@
== Queues: Serialization
-Most of the time, you can simply use GCD's default concurrent queues or the built-in queues associated with synchronized objects. However, if you want finer-gain control you can create and use your own queues.
+Most of the time, you can simply use GCD's default concurrent queues or the built-in queues associated with synchronized objects. However, if you want more precise control you can create and use your own queues.
=== Queue::for
The simplest way to create a queue is by passing in the object you want the queue +for+
puts q = Dispatch::Queue.for("my_object")
-
+ puts
+
=== Queue#join
The most common reason you want your own queue is to ensure that all pending blocks have been executed, via a +join+:
@@ -311,7 +312,9 @@
We'll start with a simple example: a +periodic+ timer that runs every 0.4 seconds and prints out the number of pending events:
- timer = Dispatch::Source.periodic(0.4) { |src| puts "Dispatch::Source.periodic: #{src.data}" }
+ timer = Dispatch::Source.periodic(0.4) do |src|
+ puts "Dispatch::Source.periodic: #{src.data}"
+ end
sleep 1 # => 1 1 ...
If you're familiar with the C API for GCD, be aware that a +Dispatch::Source+ is fully configured at the time of instantiation, and does not need to be +resume+d. Also, times are in seconds, not nanoseconds.
@@ -347,20 +350,22 @@
timer.cancel!
puts "cancel!"
-Cancellation is particularly significant in MacRuby's implementation of GCD, since (due to the reliance garbage collection) there is no other way to explicitly stop using a source.
+Cancellation is particularly significant in MacRuby's implementation of GCD, since (due to the reliance on garbage collection) there is no other way to explicitly stop using a source.
=== Custom Sources
Next up are _custom_ or _application-specific_ sources, which are fired explicitly by the developer instead of in response to an external event. These simple behaviors are the primitives upon which other sources are built.
-Like timers, these sources default to scheduling blocks on the concurrent queue. However, we will instead schedule them on our own queue, so can ensure the handler has been run.
+Like timers, these sources default to scheduling blocks on the concurrent queue. However, we will instead schedule them on our own queue, to ensure the handler has been run.
==== Source.add
-The +add+ source accumulates the sum of the event data (e.g., for numbers) in a thread-safe manner:
+The +add+ source accumulates the sum of the event data (e.g., for a counter) in a thread-safe manner:
@sum = 0
- adder = Dispatch::Source.add(q) { |s| puts "Dispatch::Source.add: #{s.data} (#{@sum += s.data})" }
+ adder = Dispatch::Source.add(q) do |s|
+ puts "Dispatch::Source.add: #{s.data} (#{@sum += s.data})"
+ end
Note that we use an instance variable (since it is re-assigned), but we don't have to +synchronize+ it -- and can safely re-assign it -- since the event handler does not need to be reentrant.
@@ -391,7 +396,10 @@
Similarly, the +or+ source combines events using a logical OR (e.g, for booleans or bitmasks):
@mask = 0
- masker = Dispatch::Source.or(q) { |s| puts "Dispatch::Source.or: #{s.data.to_s(2)} (#{(@mask |= s.data).to_s(2)})"}
+ masker = Dispatch::Source.or(q) do |s|
+ @mask |= s.data
+ puts "Dispatch::Source.or: #{s.data.to_s(2)} (#{@mask.to_s(2)})"
+ end
masker << 0b0001
q.join
puts "mask: #{@mask.to_s(2)} => 1"
@@ -414,12 +422,12 @@
This +or+-style source takes and returns a mask of different events affecting the specified +process+:
-exec::Dispatch::Source.PROC_EXEC
-exit::Dispatch::Source.PROC_EXIT
-fork::Dispatch::Source.PROC_FORK
-signal::Dispatch::Source.PROC_SIGNAL
+exec:: Dispatch::Source.PROC_EXEC
+exit:: Dispatch::Source.PROC_EXIT
+fork:: Dispatch::Source.PROC_FORK
+signal:: Dispatch::Source.PROC_SIGNAL
-_[WARNING: +Thread#fork+ is not supported by MacRuby]_
+[*WARNING*: +Thread#fork+ is not supported by MacRuby]
The underlying API expects and returns integers, e.g.:
@@ -438,13 +446,14 @@
@events = []
mask2 = [:exit, :fork, :exec, :signal]
proc_src2 = Dispatch::Source.process($$, mask2, q) do |s|
- @events += Dispatch::Source.data2events(s.data)
- puts "Dispatch::Source.process: #{Dispatch::Source.data2events(s.data)} (#{@events})"
+ this_events = Dispatch::Source.data2events(s.data)
+ @events += this_events
+ puts "Dispatch::Source.process: #{this_events} (#{@events})"
end
==== Source.process Example
-_[WARNING: Signals are only partially implemented in the current version of MacRuby, and may give erratic results]_
+[*WARNING*: Signals are only partially implemented in the current version of MacRuby, and may give erratic results]_
To fire the event, we can, e.g., send a un-trapped signal :
@@ -456,7 +465,9 @@
You can check which flags were set by _and_ing against the bitmask:
- puts "@event: #{(result = @event & mask).to_s(2)} => 1000000000000000000000000000 (Dispatch::Source::PROC_SIGNAL)"
+ result = @event & mask
+ print "@event: #{result.to_s(2)} =>"
+ puts " #{Dispatch::Source::PROC_SIGNAL} (Dispatch::Source::PROC_SIGNAL)"
proc_src.cancel!
Or equivalently, intersecting the array:
@@ -504,13 +515,13 @@
This +or+-style source takes and returns a mask of different events affecting the specified +file+:
-delete::Dispatch::Source.VNODE_DELETE
-write::Dispatch::Source.VNODE_WRITE
-extend::Dispatch::Source.VNODE_EXTEND
-attrib::Dispatch::Source.VNODE_ATTRIB
-link::Dispatch::Source.VNODE_LINK
-rename::Dispatch::Source.VNODE_RENAME
-revoke::Dispatch::Source.VNODE_REVOKE
+delete:: Dispatch::Source.VNODE_DELETE
+write:: Dispatch::Source.VNODE_WRITE
+extend:: Dispatch::Source.VNODE_EXTEND
+attrib:: Dispatch::Source.VNODE_ATTRIB
+link:: Dispatch::Source.VNODE_LINK
+rename:: Dispatch::Source.VNODE_RENAME
+revoke:: Dispatch::Source.VNODE_REVOKE
As before, the underlying API expects and returns integers, e.g.:
@@ -528,10 +539,12 @@
file.flush
file.close
q.join
- puts "fevent: #{@fevent & fmask} => #{Dispatch::Source::VNODE_WRITE} (Dispatch::Source::VNODE_WRITE)"
+ print "fevent: #{@fevent & fmask} =>"
+ puts " #{Dispatch::Source::VNODE_WRITE} (Dispatch::Source::VNODE_WRITE)"
File.delete(filename)
q.join
- puts "fevent: #{@fevent} => #{fmask} (Dispatch::Source::VNODE_DELETE | Dispatch::Source::VNODE_WRITE)"
+ print "fevent: #{@fevent} => #{fmask}"
+ puts " (Dispatch::Source::VNODE_DELETE | Dispatch::Source::VNODE_WRITE)"
file_src.cancel!
And of course can also use symbols:
@@ -563,7 +576,7 @@
end
while (@input.size < @msg.size) do; end
q.join
- puts "input: #{@input} => msg" # => e.g., 74323-2010-07-07_15:23:10_-0700
+ puts "input: #{@input} => #{@msg}" # => e.g., 74323-2010-07-07_15:23:10_-0700
reader.cancel!
Strictly speaking, the count returned by +s.data+ is only an estimate. It would be safer to instead call + at file.read(1)+ each time to avoid any risk of blocking -- but that would lead to many more block invocations, which might not be a net win.
@@ -573,18 +586,18 @@
This +add+-style event is similar to the above, but waits until a +write+ buffer is available:
file = File.open(filename, "w")
- @message = @msg.dup
+ @next_char = 0
writer = Dispatch::Source.write(file, q) do |s|
- if @message.size > 0 then
- char = @message[0]
+ if @next_char < @msg.size then
+ char = @msg[@next_char]
file.write(char)
- rest = @message[1..-1]
- puts "Dispatch::Source.write: #{char}|#{rest}"
- @message = rest
+ @next_char += 1
+ puts "Dispatch::Source.write: #{char}|#{@msg[@next_char..-1]}"
end
end
- while (@message.size > 0) do; end
- puts "output: #{File.read(filename)} => msg" # e.g., 74323-2010-07-07_15:23:10_-0700
+ while (@next_char < @msg.size) do; end
+ puts "output: #{File.read(filename)} => #{@msg}" # e.g., 74323-2010-07-07_15:23:10_-0700
+ File.delete(filename)
In this case we play it safe by only writing out a single character each time we are called, to avoid risk of blocking (and simplify our algorithm).
Modified: MacRuby/trunk/sample-macruby/Scripts/gcd/dispatch_methods.rb
===================================================================
--- MacRuby/trunk/sample-macruby/Scripts/gcd/dispatch_methods.rb 2010-07-09 01:37:55 UTC (rev 4338)
+++ MacRuby/trunk/sample-macruby/Scripts/gcd/dispatch_methods.rb 2010-07-09 18:27:19 UTC (rev 4339)
@@ -5,7 +5,7 @@
@result = job.value
puts "value (sync): #{@result} => 1.0e+50"
-job.value {|v| puts "value (async): #{v.to_int.to_s.size} => 1.0e+50" } # (eventually)
+job.value {|v| puts "value (async): #{v} => 1.0e+50" } # (eventually)
job.join
puts "join done (sync)"
@@ -76,7 +76,7 @@
print (0..4).p_map { |i| "#{10**i}\t" }.join
puts "p_map"
print (0..4).p_map(3) { |i| "#{10**i}\t" }.join
-puts "p_map(3) [sometimes fails!?!]"
+puts "p_map(3)"
mr = (0..4).p_mapreduce(0) { |i| 10**i }
puts "p_mapreduce: #{mr} => 11111"
mr = (0..4).p_mapreduce([], :concat) { |i| [10**i] }
@@ -90,16 +90,20 @@
puts (0..4).p_find_all(3) { |i| i.odd? }.inspect
puts "find | p_find | p_find(3)"
-puts (0..4).find { |i| i == 5 } # => nil
-puts (0..4).p_find { |i| i == 5 } # => nil
-puts (0..4).p_find(3) { |i| i == 5 } # => nil
+puts (0..4).find { |i| i == 5 }.nil? # => nil
+puts (0..4).p_find { |i| i == 5 }.nil? # => nil
+puts (0..4).p_find(3) { |i| i == 5 }.nil? # => nil
puts "#{(0..4).find { |i| i.odd? }} => 1"
puts "#{(0..4).p_find { |i| i.odd? }} => 1?"
puts "#{(0..4).p_find(3) { |i| i.odd? }} => 3?"
puts q = Dispatch::Queue.for("my_object")
+puts
+
q.join
-timer = Dispatch::Source.periodic(0.4) { |src| puts "Dispatch::Source.periodic: #{src.data}" }
+timer = Dispatch::Source.periodic(0.4) do |src|
+ puts "Dispatch::Source.periodic: #{src.data}"
+end
sleep 1 # => 1 1 ...
timer.suspend!
@@ -111,7 +115,9 @@
timer.cancel!
puts "cancel!"
@sum = 0
-adder = Dispatch::Source.add(q) { |s| puts "Dispatch::Source.add: #{s.data} (#{@sum += s.data})" }
+adder = Dispatch::Source.add(q) do |s|
+ puts "Dispatch::Source.add: #{s.data} (#{@sum += s.data})"
+end
adder << 1
q.join
puts "sum: #{@sum} => 1"
@@ -125,7 +131,10 @@
puts "sum: #{@sum} => 9"
adder.cancel!
@mask = 0
-masker = Dispatch::Source.or(q) { |s| puts "Dispatch::Source.or: #{s.data.to_s(2)} (#{(@mask |= s.data).to_s(2)})"}
+masker = Dispatch::Source.or(q) do |s|
+ @mask |= s.data
+ puts "Dispatch::Source.or: #{s.data.to_s(2)} (#{@mask.to_s(2)})"
+end
masker << 0b0001
q.join
puts "mask: #{@mask.to_s(2)} => 1"
@@ -147,15 +156,18 @@
@events = []
mask2 = [:exit, :fork, :exec, :signal]
proc_src2 = Dispatch::Source.process($$, mask2, q) do |s|
- @events += Dispatch::Source.data2events(s.data)
- puts "Dispatch::Source.process: #{Dispatch::Source.data2events(s.data)} (#{@events})"
+ this_events = Dispatch::Source.data2events(s.data)
+ @events += this_events
+ puts "Dispatch::Source.process: #{this_events} (#{@events})"
end
sig_usr1 = Signal.list["USR1"]
Signal.trap(sig_usr1, "IGNORE")
Process.kill(sig_usr1, $$)
Signal.trap(sig_usr1, "DEFAULT")
q.join
-puts "@event: #{(result = @event & mask).to_s(2)} => 1000000000000000000000000000 (Dispatch::Source::PROC_SIGNAL)"
+result = @event & mask
+print "@event: #{result.to_s(2)} =>"
+puts " #{Dispatch::Source::PROC_SIGNAL} (Dispatch::Source::PROC_SIGNAL)"
proc_src.cancel!
puts "@events: #{(result2 = @events & mask2)} => [:signal]"
proc_src2.cancel!
@@ -189,10 +201,12 @@
file.flush
file.close
q.join
-puts "fevent: #{@fevent & fmask} => #{Dispatch::Source::VNODE_WRITE} (Dispatch::Source::VNODE_WRITE)"
+print "fevent: #{@fevent & fmask} =>"
+puts " #{Dispatch::Source::VNODE_WRITE} (Dispatch::Source::VNODE_WRITE)"
File.delete(filename)
q.join
-puts "fevent: #{@fevent} => #{fmask} (Dispatch::Source::VNODE_DELETE | Dispatch::Source::VNODE_WRITE)"
+print "fevent: #{@fevent} => #{fmask}"
+puts " (Dispatch::Source::VNODE_DELETE | Dispatch::Source::VNODE_WRITE)"
file_src.cancel!
@fevent2 = []
@@ -216,19 +230,19 @@
end
while (@input.size < @msg.size) do; end
q.join
-puts "input: #{@input} => msg" # => e.g., 74323-2010-07-07_15:23:10_-0700
+puts "input: #{@input} => #{@msg}" # => e.g., 74323-2010-07-07_15:23:10_-0700
reader.cancel!
file = File.open(filename, "w")
- at message = @msg.dup
+ at next_char = 0
writer = Dispatch::Source.write(file, q) do |s|
- if @message.size > 0 then
- char = @message[0]
+ if @next_char < @msg.size then
+ char = @msg[@next_char]
file.write(char)
- rest = @message[1..-1]
- puts "Dispatch::Source.write: #{char}|#{rest}"
- @message = rest
+ @next_char += 1
+ puts "Dispatch::Source.write: #{char}|#{@msg[@next_char..-1]}"
end
end
-while (@message.size > 0) do; end
-puts "output: #{File.read(filename)} => msg" # e.g., 74323-2010-07-07_15:23:10_-0700
+while (@next_char < @msg.size) do; end
+puts "output: #{File.read(filename)} => #{@msg}" # e.g., 74323-2010-07-07_15:23:10_-0700
+File.delete(filename)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20100709/d80b2f39/attachment-0001.html>
More information about the macruby-changes
mailing list