On 2010 Apr 04, at 14:44, Ken Thomases wrote:
> Have you read and understood the documentation for -[NSRunLoop
> runMode:beforeDate:]?
Read? Yes. Understood? Well, probably I was misled by the way things "just
almost worked".
> ... Frankly, it seems like pure luck that it's ever exiting.
> If you schedule a timer from an operation that's running on a non-main queue,
> then that will happen on an arbitrary thread that you don't own and can't
> make any assumptions about. The timer will be scheduled on that thread's run
> loop, which is bad.
Indeed, it was on a secondary thread. Oh, so many things to think about when
you're multithreading!
> First, ...
> Second, ...
> Third, ...
> Fourth, ...
>
> Since you're already using operations, why use the above 'while' loop,
> anyway? Why not use -[NSOperationQueue waitUntilAllOperationsAreFinished].
> Or schedule a "sentinel" operation that depends on all of the other
> operations, either directly or indirectly, and then invoke -waitUntilFinished
> on it.
Alas, many of my operations call back to perform Core Data operations on the
main thread. (Syncing multiple managed object contexts never looked like much
fun to me.) The disadvantage is that this nice, clean approach you suggest
results in deadlock.
> If you prefer, you can keep using your 'while' loop and schedule such a
> "sentinel" operation on the main queue on the theory that it will count as an
> input source. While you're at it, that operation's isFinished property would
> replace the isDone flag.
I believe that my -terminateWork is part of such a sentinel operation already,
although I made my own "main queue", since this app works in 10.5 where
+[NSOperationQueue mainQueue] is not yet available. If you meant to make this
operation run on the main thread, I don't know how to do that since
-isConcurrent is ignored in Mac OS 10.6.
> If that still doesn't work, you can use
> -performSelector:withObject:afterDelay: (from the main thread) or
> -performSelectorOnMainThread:withObject:waitUntilDone: (from a background
> thread) to signal the completion. I believe either of those is known to
> count as an input source for the purposes of terminating -runMode:beforeDate:.
In the Threading Programming Guide ▸ Run Loops ▸ Input Sources, there is a
subsection titled "Cocoa Perform Selector Sources". This seems to imply that a
-performSelector::: method is indeed a run loop source, with all the
incorporated privileges and responsibilities. Although they don't explicitly
state the effect upon -runMode:beforeDate:, I see that "The run loop processes
all queued perform selector calls each time through the loop". And, it seems
to work ...
- (void)tickleRunLoop {
// No op
}
/* This method is called from the -main of the final NSOperation
in an Agent task. Like all NSOperations, it's running on a
secondary thread. */
- (void)terminateWork {
// Set the exit condition for Worker
[[AgentPerformer sharedPerformer] setIsDone:YES] ;
// Now install an input source on the main run loop, so that
// in Worker-main.m, in main(), -runLoop:beforeDate: will
// unblock, the above exit condition will be tested, found
// to be true, and cause the loop to break so that Worker
// can continue along to exit.
[self performSelectorOnMainThread:@selector(tickleRunLoop)
withObject:nil
waitUntilDone:YES] ;
}
This is actually a simple modification of the code at the end of my original
post, except that now we remember to call back to the main thread -- Thank you,
Ken!
I'm happy with this, although I suspect someone might suggest something less
kludgey.
I still wonder why my original code exitted after a 60-second timeout, though.
It's as though Apple saw me coming, and so Cocoa secretly does some kind of
"thread garbage collection" when "multithreading dummy" programming errors are
detected :)
_______________________________________________
Cocoa-dev mailing list ([email protected])
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:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com
This email sent to [email protected]