Re: NSOperationQueue broken?
Re: NSOperationQueue broken?
- Subject: Re: NSOperationQueue broken?
- From: Peter N Lewis <email@hidden>
- Date: Wed, 26 Nov 2008 11:00:09 +0900
[Reposted by request on this thread for the archives]
At 13:40 -0400 30/10/08, Michael Ash wrote:
I hate to blame an OS bug but I see no other explanation, so here we go.
I have a program which uses NSOperationQueue heavily. It uses lots of
different queues each of which has a max concurrent operation count
set to 1. In this way, the NSOperationQueue functions as a
serialization mechanism, like a lock but easier to use. This is
extremely handy.
One unusual thing it does, which I think may be the thing that kills
it, is that it often enqueues a new operation from inside of an
existing one being run on the same queue. This is to provide more
granularity for cancellation or priorities. For example, when there is
a lot of data to process, the NSOperation I enqueue just processes the
first piece of it. Then when it's done processing, it enqueues a
second NSOperation which will continue the processing. This way if I
want to cancel processing or do some higher-priority operation, it
doesn't have to wait for everything.
Anyway, I very rarely get this exception:
*** -[NSInvocationOperation start]: receiver has already started or finished
And this then crashes the app, because it's happening on an internal
NSOperationQueue thread which doesn't have an exception handler. The
rarity made this really difficult to debug, but I finally twigged to
the problem and wrote a test case which reproduces the exception
easily... on some hardware. This is that test case:
I looked through this a bit further and am sadly coming to the
conclusion that you're right, under some (quite easy to duplicate)
circumstances, the NSInvocationOperation appears to be executed by
two worker threads and chaos ensues.
As near as I can tell, it appears safe if (and perhaps only if)
addOperation only happens on the main thread (or perhaps only happens
on a single thread).
As soon as addOperation happens on multiple threads, even if the
queue is set to setMaxConcurrentOperationCount = 1, and even if no
queue ever executes more than a single NSInvocationOperation, then
the problem appears.
I adjusted Michael's test such that a new Tester object (with new
NSOperationQueue) is created each time so only a single operation is
ever executed for any given NSOperationQueue and it still results in
[NSInvocationOperation start] being called twice for the same
operation.
The only saving grace is that
performSelectorOnMainThread:@selector(addOperation:), or only calling
the addOperations from the main thread appears to resolves the
problem, which means my recent use of NSOperation in soon to be
shipping code should be safe, but I certainly would not be
recommending NSOperationQueue be used as it stands and would not have
used if I knew what I know now.
Note that I am not at all convinced that the
performSelectorOnMainThread guarantees the problem cannot happen,
simply that it appears to resolve the problem. I would not recommend
using NSOperationQueue for any purpose until this is resolved.
Very sad.
Peter.
--
Keyboard Maestro 3 Now Available!
Now With Status Menu triggers!
Keyboard Maestro <http://www.keyboardmaestro.com/> Macros for your Mac
<http://www.stairways.com/> <http://download.stairways.com/>
_______________________________________________
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