NSInvocationOperations mysteriously whacked out of NSOperationQueue
NSInvocationOperations mysteriously whacked out of NSOperationQueue
- Subject: NSInvocationOperations mysteriously whacked out of NSOperationQueue
- From: Jerry Krinock <email@hidden>
- Date: Wed, 24 Aug 2011 22:15:46 -0700
SHORT STORY
I discovered a bug in my app today caused by the following repeatable behavior: When one particular NSInvocationOperation in an NSOperationQueue executes, two others get whacked out of the queue, and thus never execute.
LONG STORY
Starting with an empty NSOperationQueue, which I have subclassed, I add 40 operations. Each operation is added as a dependency of the next operation, so that they will execute sequentially.
All but three of the operations are instances of my own subclass of NSOperation. Indexed starting with 1, these operations, numbers 17, 32 and 40, are NSInvocationOperations. Although all three of the subject invocations invoke the same target (which happens to be the operation queue) and the same selector, the three invocations are different objects, and the three invocation operations are different objects.
I am observing the queue's 'operations' using key-value observing; my observer runs whenever an operation is dequeued.
During the execution of operation 17, my observer runs, and upon debugging I see that this is because operations 32 and 40, which were there during the previous run, have been somehow whacked out of the queue! Higher-indexed operations have slid up to fill in the resulting gaps. During this time, the method invoked by these operations' invocations has executed only once, for operation 17. My observer runs again a few milliseconds later, as expected, when Operation 17 completes and is dequeued. The call stack under the observer during the double whack indicates that the perpetrator is a secondary thread executing code from the bowels of Grand Central Dispatch…
Thread-16-<com.apple.root.default-overcommit-priority>
#0 0x00103f90 in -[SSYOperationQueue observeValueForKeyPath:ofObject:change:context:] at SSYOperationQueue.m:252
#1 0x92ce98b4 in NSKeyValueNotifyObserver
#2 0x92ccf95d in -[NSObject(NSKeyValueObservingPrivate) _changeValueForKey:key:key:usingBlock:]
#3 0x92ccf525 in -[NSObject(NSKeyValueObservingPrivate) _changeValueForKey:usingBlock:]
#4 0x92cfd44d in __NSOQDelayedFinishOperations
#5 0x99de0344 in _dispatch_after_timer_callback
#6 0x99de2cc2 in _dispatch_source_invoke
#7 0x99ddf6be in _dispatch_queue_invoke
#8 0x99ddeeb8 in _dispatch_worker_thread2
#9 0x9629db24 in _pthread_wqthread
#10 0x9629f6fe in start_wqthread
Fortunately, NSInvocationOperation is only a convenience, and by simply replacing these operations with instances of my own NSOperation subclass, the problem was fixed.
Can anyone take a stab at explaining this? On one hand, I don't see how my code could be doing this, because there is no API for removing operations. But on the other hand, there is not likely to be such a heinous bug in Lion. App is built using the 10.6 SDK. I did not test the errant build in 10.6, because spending a half day on this wasn't in my schedule :|
Jerry Krinock
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden