<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"><channel><title>mikeash.com pyblog/friday-qa-2009-09-04-intro-to-grand-central-dispatch-part-ii-multi-core-performance.html comments</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2009-09-04-intro-to-grand-central-dispatch-part-ii-multi-core-performance.html#comments</link><description>mikeash.com Recent Comments</description><lastBuildDate>Sat, 06 Jun 2026 20:02:51 GMT</lastBuildDate><generator>PyRSS2Gen-1.0.0</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>Andrew Rahn - 2014-09-23 16:11:17</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2009-09-04-intro-to-grand-central-dispatch-part-ii-multi-core-performance.html#comments</link><description>Mike -- you have a typo above.  Search for dispatch_get_global_qeueue (extra e in queue).</description><guid isPermaLink="true">5c4eae1075086e718f353c56f3f5fd3e</guid><pubDate>Tue, 23 Sep 2014 16:11:17 GMT</pubDate></item><item><title>cristik - 2014-05-30 20:54:45</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2009-09-04-intro-to-grand-central-dispatch-part-ii-multi-core-performance.html#comments</link><description>Karty, is downloadImageFromRemotePath: using NSURLConnection or NSURLDownload? If yes, are you using the sync or async calls? If async, what kind of work are you doing within the delegate methods?</description><guid isPermaLink="true">600c51eb01c3541b6f3943afcc42af4e</guid><pubDate>Fri, 30 May 2014 20:54:45 GMT</pubDate></item><item><title>Karty - 2013-11-20 06:59:09</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2009-09-04-intro-to-grand-central-dispatch-part-ii-multi-core-performance.html#comments</link><description>I don't understand why the below code is blocking. Here I'm downloading a list of images and once all the images are downloaded the tableview should be reloaded. As it needs to update the UI I dispatch this async in the main queue. But this code blocks the UI.
&lt;br /&gt;
&lt;br /&gt;&lt;code&gt;
&lt;br /&gt;dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;dispatch_async(dispatch_get_main_queue(), ^{
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;dispatch_apply([self imageList].count, queue, ^(size_t index) {
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[self downloadImageFromRemotePath:[[_imageList objectAtIndex:index]];
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;});
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[[self tableView] reloadData];
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;})
&lt;br /&gt;
&lt;br /&gt;&lt;/code&gt;</description><guid isPermaLink="true">48e4e61e0383a0f03d0e72be0e99bfd6</guid><pubDate>Wed, 20 Nov 2013 06:59:09 GMT</pubDate></item><item><title>Stuart Carnie - 2009-10-01 18:32:38</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2009-09-04-intro-to-grand-central-dispatch-part-ii-multi-core-performance.html#comments</link><description>Great post Mike - thanks for the information!</description><guid isPermaLink="true">8ed1a7e40a332da3bd22abb8e7698a2d</guid><pubDate>Thu, 01 Oct 2009 18:32:38 GMT</pubDate></item><item><title>jamiehardt - 2009-09-10 20:22:53</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2009-09-04-intro-to-grand-central-dispatch-part-ii-multi-core-performance.html#comments</link><description>Thank you for posting on GCD, there's still very little practical lit on it on the webs and these demonstrations are much more edifying than Apple's.</description><guid isPermaLink="true">6653e2a010d088b203d344baceda4279</guid><pubDate>Thu, 10 Sep 2009 20:22:53 GMT</pubDate></item><item><title>mikeash - 2009-09-10 16:41:31</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2009-09-04-intro-to-grand-central-dispatch-part-ii-multi-core-performance.html#comments</link><description>Do not confuse thread safe with reentrant. They are somewhat similar but markedly different concepts.
&lt;br /&gt;
&lt;br /&gt;What you're describing is actually thread safety. Multiple independent threads of control, executing simultaneously (possibly time-sharing CPUs, but conceptually simultaneously) in the same block of code. If that block of code is thread safe, then operations complete as expected in this circumstance. If it is not thread safe, then the threads interfere with each other and Bad Things Happen. The common way to make a block of code thread safe is to wrap it in a lock, which allows only one thread into unsafe areas at a time.
&lt;br /&gt;
&lt;br /&gt;Reentrancy is very different. Click your click, then in the table of contents click "Appendix A: Thread Safety Summary". Notice how there are separate sections listing thread-safe classes and reentrant classes.
&lt;br /&gt;
&lt;br /&gt;Reentrancy is allowing the &lt;i&gt;same&lt;/i&gt; thread of control to call a block of code while that block of code is already being executed farther up the stack. 
&lt;br /&gt;
&lt;br /&gt;As an example, take one of the reentrant classes listed on that page: NSNotificationCenter. Imagine that some code posts a notification, which is then received by your code. One stack frame up from your code, NSNotificationCenter is sitting in the middle of some of its code. From within your notification handler, you decide to add a new notification observer, calling back into NSNotificationCenter even though it's still in the middle of executing.
&lt;br /&gt;
&lt;br /&gt;Reentrant means that NSNotificationCenter can handle this situation.
&lt;br /&gt;
&lt;br /&gt;Imagine if NSNotificationCenter took an NSLock at the beginning of every method, and relinquished it at the end. It would be thread safe. But the scenario I outlined above would deadlock. It would not be reentrant.
&lt;br /&gt;
&lt;br /&gt;Another, less common scenario where reentrancy is important is in signal handlers. A signal handler is executed by essentially hijacking a thread in your application and making it run the signal handler. Whatever that thread was doing at the time is just paused for the time being. Lots and lots of thread-safe APIs are completely unsafe to call from a signal handler, because those APIs achieve thread safety through locks, and the thread that was hijacked to run the signal handler may well be holding onto one of those locks, leading to a deadlock.
&lt;br /&gt;
&lt;br /&gt;To put it simply, reentrancy is basically about being thread-safe when all but one of the threads are blocked for the duration, whereas normal thread safety is about being safe when all of your threads are actively executing.
&lt;br /&gt;
&lt;br /&gt;Most of what you say is correct, as long as you think "thread safe" every time you read "reentrant".</description><guid isPermaLink="true">e742cde59dea7d47ff996b3b00cb0aec</guid><pubDate>Thu, 10 Sep 2009 16:41:31 GMT</pubDate></item><item><title>jamiehardt - 2009-09-10 07:12:05</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2009-09-04-intro-to-grand-central-dispatch-part-ii-multi-core-performance.html#comments</link><description>Hmm, maybe I'm confused... Need to do more reading.</description><guid isPermaLink="true">9f98e98281e4800b9efb0cd25130bee8</guid><pubDate>Thu, 10 Sep 2009 07:12:05 GMT</pubDate></item><item><title>jamiehardt - 2009-09-10 07:05:24</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2009-09-04-intro-to-grand-central-dispatch-part-ii-multi-core-performance.html#comments</link><description>Just to add to the general thread-safety convo -- the basic idea is that your code should be "reentrant," which means if process 1 enters your block of code, and then process 2 enters your block of code with a different set of arguments, they should both be able to play back all of the instructions in that block without messing with each other's business.
&lt;br /&gt;
&lt;br /&gt;Think of your code block (in a selector implementation, or a function, or whatever) as a recipe and the scope it runs in is a kitchen.  If you were to give this recipe to two blind cooks at the same time, does the recipe give them enough information so they don't accidently set the oven to 900 degrees, or one adds flour to a cake that's already iced, because you store a finished cake and the mixing bowl on the same counter?  A "lock" in this instance is like a step in the recipe that says "feel the counter, if it is occupied, wait until it isn't, otherwise proceed."  This way, two cooks can work in the kitchen simultaneously and share the counter -- the first will get it first, but the second only has to wait until the cook is done with the counter, and then the first cook will "relinquish" it and take over the oven, meaning the second can get to work with the counter and then wait for the oven to be available.
&lt;br /&gt;
&lt;br /&gt;Also on a more concrete note, there's a bit of reading you should do about the reentrancy of the various Apple APIs, because not all of them are, and putting many Cocoa API calls inside an async block will fail horribly -- mikeash has already gone into this a little.  AppKit is basically not reentrant: bits of it are, but anything inheiriting from NSResponder or NSView isn't, and that's most of AppKit.  The Foundation API is, except for things like NSArchiver, the mutable collection classes, and host of other things.  So keep in mind that if you are trying to write thread-safe code, not only does it have to be internally thread-safe, but anything you call must be thread-safe as well.
&lt;br /&gt;
&lt;br /&gt;&lt;a href="http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/Multithreading/Introduction/Introduction.html"&gt;http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/Multithreading/Introduction/Introduction.html&lt;/a&gt;</description><guid isPermaLink="true">c2f7d77cac83aa52db225c6c517e97e6</guid><pubDate>Thu, 10 Sep 2009 07:05:24 GMT</pubDate></item><item><title>mikeash - 2009-09-08 21:26:30</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2009-09-04-intro-to-grand-central-dispatch-part-ii-multi-core-performance.html#comments</link><description>I should also note that having the setter run asynchronously means you need to ensure that you're working with thread safe data in the setter.
&lt;br /&gt;
&lt;br /&gt;For example, if you have an NSString setter that makes a copy of the string (to avoid sharing an NSMutableString) then you should make the copy &lt;i&gt;outside&lt;/i&gt; of the setter block, so that it happens synchronously with the caller. Once you have the copy, you can then enqueue a block to actually set your instance variable to point to that copy.
&lt;br /&gt;
&lt;br /&gt;Put it another way: using locks means that setters happen synchronously with respect to both the caller and the callee. Using an asynchronous dispatch means that part of the setter happens synchronously only with respect to the caller, and part of it happens synchronously only with respect to the callee. For many things this makes no difference, but for some things you will have to split code between the two regions. This is similar to how the synchronous getter had to call autorelease outside the dispatch block to ensure that it happened on the correct thread.</description><guid isPermaLink="true">cc9201085d9ce55efefa8cf222d7d1da</guid><pubDate>Tue, 08 Sep 2009 21:26:30 GMT</pubDate></item><item><title>mikeash - 2009-09-08 21:03:04</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2009-09-04-intro-to-grand-central-dispatch-part-ii-multi-core-performance.html#comments</link><description>A good question. Maybe I'll expand on it in a future edition of Friday Q&amp;amp;A if you want to call this a topic suggestion, but here's the short version.
&lt;br /&gt;
&lt;br /&gt;A thread safe API needs to follow three rules:
&lt;br /&gt;
&lt;br /&gt;1) Synchronize all access to shared data. In other words, always take a lock (or something equivalent, like using a serial dispatch queue) before touching any shared state.
&lt;br /&gt;
&lt;br /&gt;2) Ensure that the visible state of the object is self-consistent at all times. E.g. you have separate firstName and lastName variables, you should always update them both within a single critical region so that a change from "Charlie Chang" to "Mohammed Ali" doesn't result in some poor caller getting a full name of "Mohammed Chang".
&lt;br /&gt;
&lt;br /&gt;3) Ensure that the visible state of the object is &lt;i&gt;temporally&lt;/i&gt; consistent from any given thread. In other words, if you set, and then get (and no other thread jumped in the middle) the get should reflect the set.
&lt;br /&gt;
&lt;br /&gt;(I may have forgotten some rules, since this is off the cuff, but consider these to be at least a minimum.)
&lt;br /&gt;
&lt;br /&gt;Using locks around shared data gives you 1 and 3 automatically. #2 you have to work at by making sure that all of your updates are done atomically. (Incidentally this is why the atomic attribute on ObjC @property declarations is such a bad idea; it fools you into thinking that you're safe but does nothing to achieve #2.)
&lt;br /&gt;
&lt;br /&gt;So what do dispatch queues give us?
&lt;br /&gt;
&lt;br /&gt;#1 is taken care of because the dispatch queue acts just like a lock if you ensure that all shared data access occurs on the queue.
&lt;br /&gt;
&lt;br /&gt;#2 is up to you, just like it is with locks. Ensure that your object's internal state is consistent every time you exit a block on your dispatch queue.
&lt;br /&gt;
&lt;br /&gt;#3 is probably what you're worried about. However, the use of a serial queue, and the fact that GCD guarantees that queues execute in FIFO order, ensures that this is always taken care of. Your setter executes asynchronously, this is true. However, it is guaranteed to execute before any subsequent operation. The danger would be in having a getter, enqueued afterwards, run before the setter has a chance. But this can't happen; if the setter hasn't run yet, the getter will be blocked until it has, at which point the getter will see a temporally consistent value.</description><guid isPermaLink="true">4bf807f967793491bbce0ed87af72371</guid><pubDate>Tue, 08 Sep 2009 21:03:04 GMT</pubDate></item><item><title>Nat - 2009-09-08 18:51:22</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2009-09-04-intro-to-grand-central-dispatch-part-ii-multi-core-performance.html#comments</link><description>This series is shaping up great; it's highly evocative. Thanks.
&lt;br /&gt;
&lt;br /&gt;Going back to the first part, can you elaborate on use of GCD in lieu of locks? A setter which returns immediately and does its work asynchronously seems like a race condition waiting to happen. 
&lt;br /&gt;
&lt;br /&gt;I presume I'm missing something -- all threaded programming sort of seems like a race condition waiting to happen -- but I was surprised to see that option presented matter-of-factly.</description><guid isPermaLink="true">6199d55331346ec8df7454a179286b3d</guid><pubDate>Tue, 08 Sep 2009 18:51:22 GMT</pubDate></item><item><title>Nick - 2009-09-05 16:40:28</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2009-09-04-intro-to-grand-central-dispatch-part-ii-multi-core-performance.html#comments</link><description>Excellent, much more helpful than the apple dev website(link to GCD is broken atm)</description><guid isPermaLink="true">55ad6220d2552ec504174cb9d7e0c8f4</guid><pubDate>Sat, 05 Sep 2009 16:40:28 GMT</pubDate></item></channel></rss>
