mikeash.com pyblog/friday-qa-2009-09-11-intro-to-grand-central-dispatch-part-iii-dispatch-sources.html commentshttp://www.mikeash.com/?page=pyblog/friday-qa-2009-09-11-intro-to-grand-central-dispatch-part-iii-dispatch-sources.html#commentsmikeash.com Recent CommentsThu, 28 Mar 2024 18:07:14 GMTPyRSS2Gen-1.0.0http://blogs.law.harvard.edu/tech/rssJames Alan Bush - 2016-08-22 06:38:21http://www.mikeash.com/?page=pyblog/friday-qa-2009-09-11-intro-to-grand-central-dispatch-part-iii-dispatch-sources.html#commentsAlthough veiled by generalities, the better part of Apple's documentation on GCD and threading progamming describes how GCD was used to make AVAssetReader work in conjunction with an AVSampleBufferDisplayLayer as it does [see the startReading method of AVAssetReader and the requestMediaDataWhenReadyOnQueue method of AVSampleBufferDisplayLayer], and, in particular, wherever it describes how to replace the traditional thread implementation of the producer (enqueue)/consumer(dequeue) model for acquiring and displaying frame data from a media file with the GCD equivalent [see Changing Producer-Consumer Implementations and Migrating Away From Threads, in general, in Apple's Concurrency Programming Guide]. <br /> <br />Were I using my own, custom AVAssetReader-like implementation, I would be able to read a media file via a dispatch source as shown in this post, and then periodically read frames from the file using a timer (as also shown in this post). As noted, a timer suspends a thread until it fires, which would be necessary to allow reading from other media files in cases where the number of files being read exceeds the number of files that can be read concurrently (that's about 16 on the best iPhone). <br /> <br />Without reinventing the wheel, though, how would one suspend a thread like the one spawned by the startReading method of AVAssetReader, so that other threads so spawned have a little processor time of their own? <br /> <br />As it is, I can start reading from virtually any number of AVAssetReaders, having put each in a separate thread, but calls to their corresponding AVAssetReaderTrackOutputs' copyNextSampleBuffer method are ignored beyond the 16 or so thread limit. <br /> <br />Knowing how to engineer with GCD—versus just how to program with it—is the only way to make it truly useful to you or anyone else. In the past five years since you wrote this post, could you engineer a solution for the above-stated problem? If so, evolve us, who are still merely programmers, please.92ba1e9d27bb5bb463f89a629a68bdacMon, 22 Aug 2016 06:38:21 GMTcristik - 2014-05-30 21:00:59http://www.mikeash.com/?page=pyblog/friday-qa-2009-09-11-intro-to-grand-central-dispatch-part-iii-dispatch-sources.html#commentsNo way, this post is almost 5 years old and I only find out now, after reading this article, that GCD got open sourced. Thanks a lot Mike for all the work you invested into this blog, I enjoyed every article I read on this site.2718b0ec2f01de10dd258489a6506eb2Fri, 30 May 2014 21:00:59 GMTmikeash - 2010-08-13 02:59:54http://www.mikeash.com/?page=pyblog/friday-qa-2009-09-11-intro-to-grand-central-dispatch-part-iii-dispatch-sources.html#commentsYou can't read from standard out, only write to it. If you wanted to write to it, you could create a dispatch source for <code>STDOUT_FILENO</code> so you know when you can write more data, but there's no way to read from it.0c17d5226cc10d4690c5187083234676Fri, 13 Aug 2010 02:59:54 GMTStefon - 2010-08-13 01:03:31http://www.mikeash.com/?page=pyblog/friday-qa-2009-09-11-intro-to-grand-central-dispatch-part-iii-dispatch-sources.html#commentsIf I wanted to read the standard out instead of standard in, do I just change STDIN_FILENO to STDOUT_FILENO?61fc34eb9b6e4a4d710044f20e59ce6dFri, 13 Aug 2010 01:03:31 GMTmikeash - 2009-09-14 04:16:18http://www.mikeash.com/?page=pyblog/friday-qa-2009-09-11-intro-to-grand-central-dispatch-part-iii-dispatch-sources.html#commentsYes, the proxy solution is somewhat heavyweight, but I think the magnitudes are fairly different. Even GCD's cheapness is still going to be considerably more expensive, at least in the worst case, than a few ObjC message sends and object allocations. In general, though, such an approach will only pay off if the value being promised is relatively expensive to compute. <br /> <br />I also have to wonder how often you encounter a case where you pass such a proxy into unknown code that won't use it for a while. It seems to me that in most cases, you'll control all the code and an explicit future would be simpler and faster.94cf9388b1e052253efe7a31d7a0fa3bMon, 14 Sep 2009 04:16:18 GMTjamie - 2009-09-13 21:17:40http://www.mikeash.com/?page=pyblog/friday-qa-2009-09-11-intro-to-grand-central-dispatch-part-iii-dispatch-sources.html#commentsThat's a really brilliant idea -- of course the problem I can see is that for any gain you're getting in using lightweight tasks, you might be losing by using Obj-C objects, and the concomitant heap allocations and calls to objc_msgSend(). Even without GCD, you can implement Scheme-style delay/force using NSProxy as you describe, which is essentialy what futures are, they just use static analysis to automagically decide when to turn a delay into a force. <br /> <br />I guess this just goes to show that lazy evaluation != multithreading.f92cadfe5b73048df4af5adca474f034Sun, 13 Sep 2009 21:17:40 GMTmikeash - 2009-09-12 15:34:56http://www.mikeash.com/?page=pyblog/friday-qa-2009-09-11-intro-to-grand-central-dispatch-part-iii-dispatch-sources.html#commentsSure, runloops are clever, great for what they do, etc. They're also a royal pain to work with. What modes should I add this timer to? What's the best way to signal a custom event? Is it safe to add this timer to a runloop for another thread? When do the various cycling methods/functions stop? How can I stop one early? <br /> <br />Runloops primarily exist to multiplex inputs and timers. They are, in essence, a select() loop wrapped up nicely, except using mach ports instead of file descriptors. There's really nothing to do with multithreading there, except for the fact that mach ports make for a good way to do inter-thread messaging, and thus you can use runloops to multiplex these inter-thread messages. <br /> <br />As for C++0x futures, I had not heard of these before, but looked them up and I was not impressed. Like so many things in C++, this just does not need to be a language feature. Looks like a very thin wrapper around a lock and a condition variable that really ought to be a set of library functions, not Yet Another Language feature. C++ is already an order of magnitude larger than a reasonable language, and they just keep piling things on. <br /> <br />In Objective-C you can implement transparent futures (for objects only, obviously) by writing a fairly simple NSProxy subclass. Spin off the future, crunch in the background, and if any code actually tries to query your proxy then it blocks and waits for completion. Other code never knows that it has a proxy, not the real thing. It would of course be trivial to implement these lame-brained explicit futures from C++0x as well, if you wanted to.183f6f5b3984a08ff044c59b89aba668Sat, 12 Sep 2009 15:34:56 GMTjamie - 2009-09-12 05:25:03http://www.mikeash.com/?page=pyblog/friday-qa-2009-09-11-intro-to-grand-central-dispatch-part-iii-dispatch-sources.html#comments<div class="blogcommentquote"><div class="blogcommentquoteinner">I completely disagree with your assessment of the target of GCD. I don't find run loops to be cleaner than GCD at all. Quite the opposite, in fact: I find GCD to be astonishingly clean in every respect, whereas every time I have to deal with runloops and runloop sources it's always extremely painful.</div></div> <br /> <br />Really? I always thought the reason they invented runloops is because (1) it's more efficient on a uniprocessor (like, say, a NeXT cube) and (2) because C allows threads to share data like crazy, the RunLoop gives an application developer a way of running several processes at once while never having to share data between threads. The libraries do a lot of threading, but this is all hidden from the client through the run loop source mechanism -- NSApplications are like actor objects in actor model and the event queue is their mailbox. I didn't get it for ever, but once I did it struck me as a really clever solution. <br /> <br />A complete pain to explain to anyone though. I was thinking CGD was just about the best thing for concurrency in a practical platform until someone showed me future variables in C++0x. Not out yet, but I was suddenly filled with envy again...34ad0ab08b0447bed919346b050f8392Sat, 12 Sep 2009 05:25:03 GMTJames - 2009-09-12 04:21:48http://www.mikeash.com/?page=pyblog/friday-qa-2009-09-11-intro-to-grand-central-dispatch-part-iii-dispatch-sources.html#commentskqueue(2) does now support Mach ports via EVFILT_MACHPORT.68efa2de1fee22e797e7109bd6ba702bSat, 12 Sep 2009 04:21:48 GMTKyle Sluder - 2009-09-12 01:40:16http://www.mikeash.com/?page=pyblog/friday-qa-2009-09-11-intro-to-grand-central-dispatch-part-iii-dispatch-sources.html#commentsI was indeed referring to the future. But I think it would be possible to implement the CFRunLoop API on top of GCD (and perhaps deprecate certain functionality).6e142b1f5748eab8bfdcaf3db3e7d915Sat, 12 Sep 2009 01:40:16 GMTmikeash - 2009-09-12 01:25:43http://www.mikeash.com/?page=pyblog/friday-qa-2009-09-11-intro-to-grand-central-dispatch-part-iii-dispatch-sources.html#commentsI think the main gains with retargeting CFRunLoop would be efficiency and commonality. Aside from speed, there would also presumably be some benefit to having a single common code base instead of two disparate but similar ones. <br /> <br />The capabilities don't match too closely, though. Thinking about this more, it's a lot more than just modes. A major example: CFRunLoop is reentrant, and can be manually cycled. GCD has no such facilities at this time. <br /> <br />I completely disagree with your assessment of the target of GCD. I don't find run loops to be cleaner than GCD at all. Quite the opposite, in fact: I find GCD to be astonishingly clean in every respect, whereas every time I have to deal with runloops and runloop sources it's always extremely painful. GCD is a game-changing system-integrated multiprocessing and event processing library. That you see this as being something to lure developers over from other platforms which no "real" Mac programmer will use does not make any sense to me.8b1a157ed8631e348f102a9118a2f7e2Sat, 12 Sep 2009 01:25:43 GMTjamie - 2009-09-11 23:41:17http://www.mikeash.com/?page=pyblog/friday-qa-2009-09-11-intro-to-grand-central-dispatch-part-iii-dispatch-sources.html#commentsThe "CFRunLoop replacement" occurred to me as well when I first saw this, but I'm not sure it would necesssarily make it easier to build a Cocoa application to simply replace all of the "performSelectorOnMainThread:" calls with dispatch_async calls pushing tasks on the main thread's queue. A queue seems like a much more clever way of working with the main thread, and I can see how people at NeXT would see dispatch and say "damn I wish we had that in 1988!", but given the current state of things, it seems like it'd be hard to replace CFRunLoop with a serial queue without completely ripping Cocoa apart, and again, the only gain you get is turning a run loop source into a dispatch source, which may run faster but won't be any easier to code or read. <br /> <br />OTOH, dispatch queues seem to be targeted squarely at new developers coming to Mac OS from Java and Windows who are completely turned-off by the whole run loop concept -- just based on my conversations with Blackberry and Windows developers coming from those environments, they find threading complicated, but an easier concept to understand than registering functions and delegates as "run loop sources" and all of that, even if run loops are much cleaner solutions given the way C works. <br /> <br />I personally can't wait to finish my special alertPanel class that runs -- <br /> <br />panelWithTitle:(NSString *)title informationalText:(NSString *)text onError:(void(^errorBlock)) onButtonClicked:(void(^buttonBlock)(int)) 9537a5d09774fbc536b1c7c2e4122f17Fri, 11 Sep 2009 23:41:17 GMTmikeash - 2009-09-11 21:31:22http://www.mikeash.com/?page=pyblog/friday-qa-2009-09-11-intro-to-grand-central-dispatch-part-iii-dispatch-sources.html#commentsI don't know if you mean currently or in the future. Currently, we can see from the source release that CFRunLoop is not implemented on top of GCD, and that GCD has special code to integrate the GCD main queue with CFRunLoop. <br /> <br />For the future, I don't think CFRunLoop will become a thin wrapper around GCD, because the feature sets aren't quite identical. The main problem I see is the existence of modes. A single CFRunLoop can be put into different modes which have different sources installed. Any given source can be installed on one or more mode. As far as I can tell, GCD has no real equivalent to this. Perhaps something could be done using target queues? I could certainly be wrong, but they don't quite seem like they would fit together.bb0a1fe9e01fc855f219331402ebf9a8Fri, 11 Sep 2009 21:31:22 GMTKyle Sluder - 2009-09-11 20:41:39http://www.mikeash.com/?page=pyblog/friday-qa-2009-09-11-intro-to-grand-central-dispatch-part-iii-dispatch-sources.html#commentsI'm wondering if we're looking at a new basis for CFRunLoop here…36a8766decb08f2171c9dc41428a74d6Fri, 11 Sep 2009 20:41:39 GMT