[MacRuby] #1393: Invocation of blocks registered using -[NSNotificationCenter addObserverForName:object:queue:usingBlock:] is unreliable

MacRuby ruby-noreply at macosforge.org
Thu Sep 29 08:59:30 PDT 2011


#1393: Invocation of blocks registered using -[NSNotificationCenter
addObserverForName:object:queue:usingBlock:] is unreliable
--------------------------------+-------------------------------------------
 Reporter:  sohocoke@…          |       Owner:  lsansonetti@…        
     Type:  defect              |      Status:  new                  
 Priority:  blocker             |   Milestone:                       
Component:  MacRuby             |    Keywords:                       
--------------------------------+-------------------------------------------
 It seems that when a block / proc is registered for notification (cf. a
 selector), its invocation occasionally fails.

 Here is a program that, occasionally, reproduces the case.
 notification-test.rb
 {{{
 # reduced case of block-based observation

 framework 'cocoa'
 require 'thread'

 class TestSender
   def send
     NSNotificationCenter.defaultCenter.postNotification
 NSNotification.notificationWithName(:kTestNotification, object:[1, 2, 3])
   end
 end

 class ObjectWithCounter
   attr_reader :counter

   def initialize
     super
     @counter = 0
     @mutex = Mutex.new
   end

   def increment
     @mutex.synchronize  {
       @counter += 1
     }
   end
 end

 class Observer1 < ObjectWithCounter
   def listen_with_block
     NSNotificationCenter.defaultCenter.addObserverForName
 :kTestNotification, object:nil, queue:nil, usingBlock:Proc.new {
 |notification|
       NSLog("#{self} notified - in block now.")
       self.increment
     }
   end
 end

 class Observer2 < ObjectWithCounter
   def listen_with_callback
     NSNotificationCenter.defaultCenter.addObserver self,
 selector:"handle_notification:", name: :kTestNotification, object:nil
   end

   def handle_notification(notification)
     NSLog("#{self} notified of #{notification} - in handler now.")
     self.increment
   end
 end


 mutex = Mutex.new
 o1_counter, o2_counter = 0, 0
 30.times do
   sender = TestSender.new

   o1 = Observer1.new
   o1.listen_with_block
   sender.send

   o2 = Observer2.new
   o2.listen_with_callback
   sender.send

   mutex.synchronize do
     o1_counter += o1.counter
     o2_counter += o2.counter
   end
 end

 puts "o1 notified #{o1_counter} times."
 puts "o2 notified #{o2_counter} times."

 # expect to have o1 notified 60 times, o2 30 times.
 }}}

 I ran it thusly and observed the output:
 {{{
 [~/dev/src/mac/macruby]$ while [ 0 ]; do
 ruby notification-test.rb >> notification-test.out
 done
 [~/dev/src/mac/macruby]$ grep 'notified' notification-test.out
 o1 notified 60 times.
 o2 notified 30 times.
 o1 notified 59 times.
 o2 notified 30 times.
 o1 notified 59 times.
 o2 notified 30 times.
 o1 notified 58 times.
 o2 notified 30 times.

 }}}

 i (hastily) threw in some mutexes after a first version of the test
 program on paranoia of there being a silly threading mistake, but
 documentation for the method on NSNotificationCenter suggests that the
 erroneous invocation should occur synchronously on the main thread of the
 program anyway.

 I tried macruby-0.10 and macruby-nightly installed via rvm.

-- 
Ticket URL: <http://www.macruby.org/trac/ticket/1393>
MacRuby <http://macruby.org/>



More information about the macruby-tickets mailing list