{"id":1609,"date":"2009-02-17T12:58:41","date_gmt":"2009-02-17T18:58:41","guid":{"rendered":"http:\/\/bobbeaty.com\/wp\/?p=1609"},"modified":"2009-03-04T13:49:17","modified_gmt":"2009-03-04T19:49:17","slug":"interesting-application-of-thread-safe-lockless-data-structures","status":"publish","type":"post","link":"https:\/\/bobbeaty.com\/wp\/archives\/1609","title":{"rendered":"Interesting Application of Thread-Safe Lockless Data Structures"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/bobbeaty.com\/wp\/wp-content\/uploads\/2007\/10\/cplusplus.jpg\" alt=\"cplusplus.jpg\" border=\"0\" width=\"150\" height=\"149\" align=\"right\" \/><\/p>\n<p>I was looking at lockless data structures for multi-threaded programming again this morning, and I came across a link to <a href=\"http:\/\/transactionkit.sourceforge.net\/\">TransactionKit<\/a>. This sounds very interesting to me. Basically, the group has implemented a thread-safe <tt>NSDictionary<\/tt> and <tt>NSMutableDictionary<\/tt> pair that are completely safe for multi-threaded environments, use no locks, and offer the <strong>basics<\/strong> of transactional integrity: <tt>begin transaction<\/tt>, <tt>commit<\/tt> and <tt>rollback<\/tt> functionality. And I have to admit I'm very intrigued.<\/p>\n<p>The biggest challenge to me in working with these lockless data structures is that you <em>might<\/em> not know you're going to need them when you start the project. It's only <strong><em>after<\/em><\/strong> you build the project, see it scale for a while, and then hit a fundamental limit that you see it's time to switch over. Problem is, by then, you're stuck. You've got all this code that uses one form of thread-safety, and now what you realize you need is something else all together. But you can't justify the complete re-write.<\/p>\n<p>What you need is lockless <strong><em>alternatives<\/em><\/strong> to standard data components that are easily swapped in when the 'going gets tough'. For example, I like <a href=\"http:\/\/transactionkit.sourceforge.net\/\">TransactionKit<\/a>'s take on the inclusion in Objective-C - make it look like a simple <tt>NSDictionary<\/tt> and <tt>NSMutableDictionary<\/tt> so that it's a simple search and replace for the vast majority of the retrofitting. This makes things a lot simpler.<\/p>\n<p>But now I'm looking at the CKit stuff. It'd be one thing to have a <em>truly<\/em> lockless <tt>CKFIFOQueue<\/tt>. Then another that uses mutexes for those times when it's not a major issue for speed. Finally, one that uses the lockless atomic calls to make it <strong><em>appear<\/em><\/strong> to be lockless, in fact, you can even simply No-Op the <tt>lock()<\/tt> and <tt>unlock()<\/tt> methods in the subclass, but all the while, the thread-safe behavior is in play.<\/p>\n<p>The problems with general coding are a lot more difficult, however. Take for example, the <tt>retain<\/tt>\/<tt>release<\/tt> code I posted a few days ago. That's not so simple. Previously, I had:<\/p>\n<pre class=\"cpp\" style=\"font-family:monospace;\"><span style=\"color: #0000ff;\">void<\/span> Instrument<span style=\"color: #008080;\">::<\/span><span style=\"color: #007788;\">retain<\/span><span style=\"color: #008000;\">&#40;<\/span><span style=\"color: #008000;\">&#41;<\/span>\n<span style=\"color: #008000;\">&#123;<\/span>\n    <span style=\"color: #666666;\">\/\/ first, lock this guy up<\/span>\n    CKStackLocker      lockem<span style=\"color: #008000;\">&#40;<\/span><span style=\"color: #000040;\">&amp;<\/span>mRetainReleaseMutex<span style=\"color: #008000;\">&#41;<\/span><span style=\"color: #008080;\">;<\/span>\n    <span style=\"color: #666666;\">\/\/ now up the count<\/span>\n    <span style=\"color: #000040;\">++<\/span>mRetainReleaseCount<span style=\"color: #008080;\">;<\/span>\n    <span style=\"color: #666666;\">\/\/ see if it's in the pool to be released, if so, remove it<\/span>\n    <span style=\"color: #0000ff;\">if<\/span> <span style=\"color: #008000;\">&#40;<\/span>mRetainReleaseCount <span style=\"color: #000080;\">==<\/span> <span style=\"color: #0000dd;\">1<\/span><span style=\"color: #008000;\">&#41;<\/span> <span style=\"color: #008000;\">&#123;<\/span>\n        CKStackLocker      lockem<span style=\"color: #008000;\">&#40;<\/span><span style=\"color: #000040;\">&amp;<\/span>mReleasePoolMutex<span style=\"color: #008000;\">&#41;<\/span><span style=\"color: #008080;\">;<\/span>\n        mReleasePool.<span style=\"color: #0000dd;\">remove<\/span><span style=\"color: #008000;\">&#40;<\/span><span style=\"color: #0000dd;\">this<\/span><span style=\"color: #008000;\">&#41;<\/span><span style=\"color: #008080;\">;<\/span>\n    <span style=\"color: #008000;\">&#125;<\/span>\n<span style=\"color: #008000;\">&#125;<\/span>\n&nbsp;\n<span style=\"color: #0000ff;\">void<\/span> Instrument<span style=\"color: #008080;\">::<\/span><span style=\"color: #007788;\">release<\/span><span style=\"color: #008000;\">&#40;<\/span><span style=\"color: #008000;\">&#41;<\/span>\n<span style=\"color: #008000;\">&#123;<\/span>\n    <span style=\"color: #666666;\">\/\/ first, lock this guy up<\/span>\n    CKStackLocker      lockem<span style=\"color: #008000;\">&#40;<\/span><span style=\"color: #000040;\">&amp;<\/span>mRetainReleaseMutex<span style=\"color: #008000;\">&#41;<\/span><span style=\"color: #008080;\">;<\/span>\n    <span style=\"color: #666666;\">\/\/ no decrease the count<\/span>\n    <span style=\"color: #000040;\">--<\/span>mRetainReleaseCount<span style=\"color: #008080;\">;<\/span>\n    <span style=\"color: #666666;\">\/\/ see if it's an error<\/span>\n    <span style=\"color: #0000ff;\">if<\/span> <span style=\"color: #008000;\">&#40;<\/span>mRetainReleaseCount <span style=\"color: #000080;\">&lt;<\/span> <span style=\"color: #0000dd;\">0<\/span><span style=\"color: #008000;\">&#41;<\/span> <span style=\"color: #008000;\">&#123;<\/span>\n        getLog<span style=\"color: #008000;\">&#40;<\/span><span style=\"color: #008000;\">&#41;<\/span> <span style=\"color: #000080;\">&lt;&lt;<\/span> l_error.<span style=\"color: #007788;\">setErrorId<\/span><span style=\"color: #008000;\">&#40;<\/span><span style=\"color: #FF0000;\">&quot;Instrument.release&quot;<\/span><span style=\"color: #008000;\">&#41;<\/span>\n                 <span style=\"color: #000080;\">&lt;&lt;<\/span> <span style=\"color: #FF0000;\">&quot;the release count for &quot;<\/span> <span style=\"color: #000080;\">&lt;&lt;<\/span> mmSym<span style=\"color: #008000;\">&#40;<\/span><span style=\"color: #008000;\">&#41;<\/span> <span style=\"color: #000080;\">&lt;&lt;<\/span> <span style=\"color: #FF0000;\">&quot; went negative! (&quot;<\/span>\n                 <span style=\"color: #000080;\">&lt;&lt;<\/span> mRetainReleaseCount <span style=\"color: #000080;\">&lt;&lt;<\/span> <span style=\"color: #FF0000;\">&quot;) This is a serious problem.&quot;<\/span> <span style=\"color: #000080;\">&lt;&lt;<\/span> endl<span style=\"color: #008080;\">;<\/span>\n    <span style=\"color: #008000;\">&#125;<\/span>\n    <span style=\"color: #666666;\">\/\/ see if it's at zero, and then if so, add it to the pool<\/span>\n    <span style=\"color: #0000ff;\">if<\/span> <span style=\"color: #008000;\">&#40;<\/span>mRetainReleaseCount <span style=\"color: #000080;\">&lt;=<\/span> <span style=\"color: #0000dd;\">0<\/span><span style=\"color: #008000;\">&#41;<\/span> <span style=\"color: #008000;\">&#123;<\/span>\n        CKStackLocker      lockem<span style=\"color: #008000;\">&#40;<\/span><span style=\"color: #000040;\">&amp;<\/span>mReleasePoolMutex<span style=\"color: #008000;\">&#41;<\/span><span style=\"color: #008080;\">;<\/span>\n        <span style=\"color: #0000ff;\">if<\/span> <span style=\"color: #008000;\">&#40;<\/span><span style=\"color: #000040;\">!<\/span>mReleasePool.<span style=\"color: #007788;\">contains<\/span><span style=\"color: #008000;\">&#40;<\/span><span style=\"color: #0000dd;\">this<\/span><span style=\"color: #008000;\">&#41;<\/span><span style=\"color: #008000;\">&#41;<\/span> <span style=\"color: #008000;\">&#123;<\/span>\n            <span style=\"color: #666666;\">\/\/ log that we're going to dump it in the trash<\/span>\n            getLog<span style=\"color: #008000;\">&#40;<\/span><span style=\"color: #008000;\">&#41;<\/span> <span style=\"color: #000080;\">&lt;&lt;<\/span> l_error.<span style=\"color: #007788;\">setErrorId<\/span><span style=\"color: #008000;\">&#40;<\/span><span style=\"color: #FF0000;\">&quot;Instrument.release&quot;<\/span><span style=\"color: #008000;\">&#41;<\/span>\n                     <span style=\"color: #000080;\">&lt;&lt;<\/span> <span style=\"color: #FF0000;\">&quot;adding &quot;<\/span> <span style=\"color: #000080;\">&lt;&lt;<\/span> mmSym<span style=\"color: #008000;\">&#40;<\/span><span style=\"color: #008000;\">&#41;<\/span> <span style=\"color: #000080;\">&lt;&lt;<\/span> <span style=\"color: #FF0000;\">&quot; with retain cnt=&quot;<\/span>\n                     <span style=\"color: #000080;\">&lt;&lt;<\/span> mRetainReleaseCount <span style=\"color: #000080;\">&lt;&lt;<\/span> <span style=\"color: #FF0000;\">&quot; to garbage&quot;<\/span> <span style=\"color: #000080;\">&lt;&lt;<\/span> endl<span style=\"color: #008080;\">;<\/span>\n            <span style=\"color: #666666;\">\/\/ ...and then do it.<\/span>\n            mReleasePool.<span style=\"color: #007788;\">addBack<\/span><span style=\"color: #008000;\">&#40;<\/span><span style=\"color: #0000dd;\">this<\/span><span style=\"color: #008000;\">&#41;<\/span><span style=\"color: #008080;\">;<\/span>\n        <span style=\"color: #008000;\">&#125;<\/span>\n    <span style=\"color: #008000;\">&#125;<\/span>\n<span style=\"color: #008000;\">&#125;<\/span><\/pre>\n<p>where the critical points were one (1) in the <tt>retain()<\/tt> code and anything less than or equal to zero in the <tt>release()<\/tt> code. This was due to the logical assumption that the value of <tt>mRetainReleaseCount<\/tt> would be initialized to 1. But what if we have it initialized to zero? Then the critical points are zero for the <tt>retain()<\/tt> code and anything negative for the <tt>release()<\/tt> code.<\/p>\n<pre class=\"cpp\" style=\"font-family:monospace;\"><span style=\"color: #339900;\">#include &lt;asm\/atomic.h&gt;<\/span>\n&nbsp;\n<span style=\"color: #0000ff;\">void<\/span> Instrument<span style=\"color: #008080;\">::<\/span><span style=\"color: #007788;\">retain<\/span><span style=\"color: #008000;\">&#40;<\/span><span style=\"color: #008000;\">&#41;<\/span>\n<span style=\"color: #008000;\">&#123;<\/span>\n    <span style=\"color: #ff0000; font-style: italic;\">\/*\n     * Increment the count. If it's zero, then we were ready to flush this guy\n     * and now we need to pull him out of the garbage before he gets flushed.\n     *\/<\/span>\n    <span style=\"color: #0000ff;\">if<\/span> <span style=\"color: #008000;\">&#40;<\/span>atomic_inc_and_test<span style=\"color: #008000;\">&#40;<\/span><span style=\"color: #000040;\">&amp;<\/span>mRetainReleaseCount<span style=\"color: #008000;\">&#41;<\/span><span style=\"color: #008000;\">&#41;<\/span> <span style=\"color: #008000;\">&#123;<\/span>\n        CKStackLocker      lockem<span style=\"color: #008000;\">&#40;<\/span><span style=\"color: #000040;\">&amp;<\/span>mReleasePoolMutex<span style=\"color: #008000;\">&#41;<\/span><span style=\"color: #008080;\">;<\/span>\n        mReleasePool.<span style=\"color: #0000dd;\">remove<\/span><span style=\"color: #008000;\">&#40;<\/span><span style=\"color: #0000dd;\">this<\/span><span style=\"color: #008000;\">&#41;<\/span><span style=\"color: #008080;\">;<\/span>\n    <span style=\"color: #008000;\">&#125;<\/span>\n<span style=\"color: #008000;\">&#125;<\/span>\n&nbsp;\n<span style=\"color: #0000ff;\">void<\/span> Instrument<span style=\"color: #008080;\">::<\/span><span style=\"color: #007788;\">release<\/span><span style=\"color: #008000;\">&#40;<\/span><span style=\"color: #008000;\">&#41;<\/span>\n<span style=\"color: #008000;\">&#123;<\/span>\n    <span style=\"color: #ff0000; font-style: italic;\">\/*\n     * Decrement the count, and if we are negative then it's time to add this\n     * guy to the release pool for deletion.\n     *\/<\/span>\n    <span style=\"color: #0000ff;\">if<\/span> <span style=\"color: #008000;\">&#40;<\/span>atomic_add_negative<span style=\"color: #008000;\">&#40;<\/span><span style=\"color: #000040;\">-<\/span><span style=\"color: #0000dd;\">1<\/span>, <span style=\"color: #000040;\">&amp;<\/span>mRetainReleaseCount<span style=\"color: #008000;\">&#41;<\/span><span style=\"color: #008000;\">&#41;<\/span> <span style=\"color: #008000;\">&#123;<\/span>\n        CKStackLocker      lockem<span style=\"color: #008000;\">&#40;<\/span><span style=\"color: #000040;\">&amp;<\/span>mReleasePoolMutex<span style=\"color: #008000;\">&#41;<\/span><span style=\"color: #008080;\">;<\/span>\n        <span style=\"color: #0000ff;\">if<\/span> <span style=\"color: #008000;\">&#40;<\/span><span style=\"color: #000040;\">!<\/span>mReleasePool.<span style=\"color: #007788;\">contains<\/span><span style=\"color: #008000;\">&#40;<\/span><span style=\"color: #0000dd;\">this<\/span><span style=\"color: #008000;\">&#41;<\/span><span style=\"color: #008000;\">&#41;<\/span> <span style=\"color: #008000;\">&#123;<\/span>\n            <span style=\"color: #666666;\">\/\/ log that we're going to dump it in the trash<\/span>\n            getLog<span style=\"color: #008000;\">&#40;<\/span><span style=\"color: #008000;\">&#41;<\/span> <span style=\"color: #000080;\">&lt;&lt;<\/span> l_error.<span style=\"color: #007788;\">setErrorId<\/span><span style=\"color: #008000;\">&#40;<\/span><span style=\"color: #FF0000;\">&quot;Instrument.release&quot;<\/span><span style=\"color: #008000;\">&#41;<\/span>\n                     <span style=\"color: #000080;\">&lt;&lt;<\/span> <span style=\"color: #FF0000;\">&quot;adding &quot;<\/span> <span style=\"color: #000080;\">&lt;&lt;<\/span> mmSym<span style=\"color: #008000;\">&#40;<\/span><span style=\"color: #008000;\">&#41;<\/span> <span style=\"color: #000080;\">&lt;&lt;<\/span> <span style=\"color: #FF0000;\">&quot; with retain cnt=&quot;<\/span>\n                     <span style=\"color: #000080;\">&lt;&lt;<\/span> mRetainReleaseCount <span style=\"color: #000080;\">&lt;&lt;<\/span> <span style=\"color: #FF0000;\">&quot; to garbage&quot;<\/span> <span style=\"color: #000080;\">&lt;&lt;<\/span> endl<span style=\"color: #008080;\">;<\/span>\n            <span style=\"color: #666666;\">\/\/ ...and then do it.<\/span>\n            mReleasePool.<span style=\"color: #007788;\">addBack<\/span><span style=\"color: #008000;\">&#40;<\/span><span style=\"color: #0000dd;\">this<\/span><span style=\"color: #008000;\">&#41;<\/span><span style=\"color: #008080;\">;<\/span>\n        <span style=\"color: #008000;\">&#125;<\/span>\n    <span style=\"color: #008000;\">&#125;<\/span>\n<span style=\"color: #008000;\">&#125;<\/span><\/pre>\n<p>if I then initialize the value of <tt>mRetainReleaseCount<\/tt> with:<\/p>\n<pre class=\"cpp\" style=\"font-family:monospace;\">    ...\n    <span style=\"color: #007788;\">mRetainReleaseCount<\/span><span style=\"color: #008000;\">&#40;<\/span>ATOMIC_INIT<span style=\"color: #008000;\">&#40;<\/span><span style=\"color: #0000dd;\">0<\/span><span style=\"color: #008000;\">&#41;<\/span><span style=\"color: #008000;\">&#41;<\/span>,\n    ...<\/pre>\n<p>in the constructor's code, then we'll start with zero, climb positive, and then when we go negative we'll by tossed into the release pool for the next cycle on the garbage collector thread. Since the garbage collector thread also checks the retain\/release count before it wipes out the instance, we're safe.<\/p>\n<p>At least I'm pretty sure we are...<\/p>\n<p>Well... here's the problem I see now. Because we have removed the mutex on the <tt>retain()<\/tt> and <tt>release()<\/tt> methods, we <em>can<\/em> be doing both at once. The count will be handled properly, but what if the <tt>release()<\/tt> hits it's counter operation <em>first<\/em>, but the <tt>retain()<\/tt> method's <tt>if()<\/tt> body executes first to get the lock on the second mutex?<\/p>\n<p>Now we're in trouble. The counter will be saying 'leave the instrument out of the pool', but the code will execute in the order indicating that the instance will be placed <strong><em>into<\/em><\/strong> the pool. Crud.<\/p>\n<p>Yup, this is not easy. I was ready to put the code into play, but there's no guarantee that the body of the conditional will execute in the same order as the atomic operation. This means that it's possible to have them in the wrong order. This, in turn, tells me that the greatest application of these atomic operations are in the thread-safe lockless data structures. That's about it. When you have two operations that need to be treated atomically, then you're sunk. Darn.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I was looking at lockless data structures for multi-threaded programming again this morning, and I came across a link to TransactionKit. This sounds very interesting to me. Basically, the group has implemented a thread-safe NSDictionary and NSMutableDictionary pair that are completely safe for multi-threaded environments, use no locks, and offer the basics of transactional integrity: [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3],"tags":[],"class_list":["post-1609","post","type-post","status-publish","format-standard","hentry","category-coding"],"_links":{"self":[{"href":"https:\/\/bobbeaty.com\/wp\/wp-json\/wp\/v2\/posts\/1609","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/bobbeaty.com\/wp\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/bobbeaty.com\/wp\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/bobbeaty.com\/wp\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/bobbeaty.com\/wp\/wp-json\/wp\/v2\/comments?post=1609"}],"version-history":[{"count":3,"href":"https:\/\/bobbeaty.com\/wp\/wp-json\/wp\/v2\/posts\/1609\/revisions"}],"predecessor-version":[{"id":1711,"href":"https:\/\/bobbeaty.com\/wp\/wp-json\/wp\/v2\/posts\/1609\/revisions\/1711"}],"wp:attachment":[{"href":"https:\/\/bobbeaty.com\/wp\/wp-json\/wp\/v2\/media?parent=1609"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/bobbeaty.com\/wp\/wp-json\/wp\/v2\/categories?post=1609"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/bobbeaty.com\/wp\/wp-json\/wp\/v2\/tags?post=1609"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}