mikeash.com pyblog/late-night-cocoa.html commentshttp://www.mikeash.com/?page=pyblog/late-night-cocoa.html#commentsmikeash.com Recent CommentsFri, 29 Mar 2024 05:53:45 GMTPyRSS2Gen-1.0.0http://blogs.law.harvard.edu/tech/rssDiogo Tridapalli - 2013-01-29 20:25:37http://www.mikeash.com/?page=pyblog/late-night-cocoa.html#commentsHi Mike, <br /> <br />The link is broken. <br /> <br />[]'sbad3b850cfb30ac882ef1faba519f654Tue, 29 Jan 2013 20:25:37 GMTJonathan Dann - 2008-09-19 06:36:50http://www.mikeash.com/?page=pyblog/late-night-cocoa.html#commentsHi Mike, <br /> <br />Thanks for those, I appreciate you taking the time to give examples too. It's far easier to read code than listen to it! <br /> <br />I'm using NSOperation at the moment, but now I have a good starting point to see what mileage I can get from these functions. <br /> <br />Thanks again, <br /> <br />Jonathan5684eaff44166ac245c353b135e14444Fri, 19 Sep 2008 06:36:50 GMTmikeash - 2008-09-09 02:13:39http://www.mikeash.com/?page=pyblog/late-night-cocoa.html#commentsJonathan, thanks for your kind words. <br /> <br />I'd suggest that these techniques are probably not too useful for things like string searching. If you can break it up into smallish work units, then I recommend using NSOperation and NSOperationQueue (if you can require 10.5) to run them on all available CPU cores. But of course you know your problem space better than I do, so certainly check out everything and come to your own conclusions. <br /> <br />I will give some quick examples though. Beware that all of the below is written in this comment box and has not been tested. <br /> <br />First, a quick re-implementation of that atomic increment function I used as an example in the podcast. This gives an illustration of the fetch/update/commit loop that I discussed: <br /> <br /><code>int32_t AtomicIncrementInt32(volatile int32_t *intptr) <br />{ <br />&nbsp;&nbsp;&nbsp;&nbsp;bool success; <br />&nbsp;&nbsp;&nbsp;&nbsp;int32_t old; <br />&nbsp;&nbsp;&nbsp;&nbsp;int32_t new; <br />&nbsp;&nbsp;&nbsp;&nbsp;do { <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;old = *intptr; // fetch <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;new = old + 1; // update <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;success = OSAtomicCompareAndSwap32Barrier(old, new, intptr); // commit <br />&nbsp;&nbsp;&nbsp;&nbsp;} while(!success); // if commit failed, do it again <br />&nbsp;&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;return new; // it can be useful to know what the end result was <br />}</code> <br /> <br />And now here's an illustration of inserting into a linked list. First we need to define a structure for the list nodes: <br /> <br /><code>struct ListNode <br />{ <br />&nbsp;&nbsp;&nbsp;&nbsp;id payload; <br />&nbsp;&nbsp;&nbsp;&nbsp;struct ListNode *next; <br />}</code> <br /> <br />(The 'payload' member can be replaced with anything, even a whole collection of different members. What it contains is up to you.) <br /> <br />And now, the insert function: <br /> <br /><code>void AtomicInsertListNodeAtHead(struct ListNode * volatile *head, struct ListNode *newnode) <br />{ <br />&nbsp;&nbsp;&nbsp;&nbsp;bool success; <br />&nbsp;&nbsp;&nbsp;&nbsp;struct ListNode oldhead; <br />&nbsp;&nbsp;&nbsp;&nbsp;do { <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;oldhead = *head; // fetch <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;newnode-&gt;next = oldhead; // update <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;success = OSAtomicCompareAndSwapPtrBarrier(oldhead, newnode, head); // commit <br />&nbsp;&nbsp;&nbsp;&nbsp;} while(!success); <br />}</code> <br /> <br />This follows the same basic pattern. Here, we update the next pointer to point at the old head. Then we do the CAS to replace the head pointer. If it fails, something else updated the list before we could, so start over. <br /> <br />Note, avoid the temptation to write a <code>AtomicRemoveListNodeAtHead</code> function using this same basic pattern. It may look easy, but you run into that ABA problem I discussed and that is extremely non-trivial to solve. <br /> <br />So, what if you really do want to support removal? Well, that's where that built-in atomic queue stuff comes in. Instead of writing our own list node stuff, we can use Apple's: <br /> <br /><code>OSQueueHead queue = OS_ATOMIC_QUEUE_INIT; <br /> <br />OSAtomicEnqueue(&amp;queue, newnode, offsetof(struct ListNode, next)); <br /> <br />struct ListNode *dequeued = OSAtomicDequeue(&amp;queue, offsetof(struct ListNode, next));</code> <br /> <br />And Apple takes care of solving all that ABA nastiness and wrapping it all up in a couple of really simple functions.71a923b30ea6a511b4930f8cf68966d9Tue, 09 Sep 2008 02:13:39 GMTJonathan Dann - 2008-09-06 20:40:57http://www.mikeash.com/?page=pyblog/late-night-cocoa.html#commentsHi Mike, <br /> <br />Really liked the episode, although you said that Apple had done the hard work you still made it comprehensible. <br /> <br />Do you have any example code that would demonstrate some of these operations? I do a lot of string searching in my app and it's be fun to see if I can improve performance with these. <br /> <br />Thanks, <br /> <br />Jonathan649a800f2fbe446ff81825bbe4443901Sat, 06 Sep 2008 20:40:57 GMTmikeash - 2008-09-06 10:39:31http://www.mikeash.com/?page=pyblog/late-night-cocoa.html#commentsGlad you liked it. I'm not surprised that you found it slow at the beginning. I really wanted to justify the approach and put it into context, and that meant a discussion of more traditional multithreading which is pretty much just a retread for anyone who's already very familiar with it.afcedebd5cfb209944cb30e7baaf10a2Sat, 06 Sep 2008 10:39:31 GMTfoobaz - 2008-09-06 10:22:45http://www.mikeash.com/?page=pyblog/late-night-cocoa.html#commentsThanks, this is relevant to my interests. The show started out a little slow but it got interesting about 20:00.4ebbfa658f9a1ec403074ec259c277f4Sat, 06 Sep 2008 10:22:45 GMT