title: Synchronizing read/write access to an instance variable for high performance in iOS?
body: <p>What's the best way / least wait-causing way to synchronize read/write access to an instance variable in objective-c for iOS?</p>
  
  <p>The variable gets read and written very often (let's say 1000 times per second read and written). It is not important that changes take effect immediately. It is not even important that reads get consistent data with one-another, but writes must sooner or later be reflected in the data acquired by reads. Is there some data structure which allows this?</p>
  
  <p>I thought of this:</p>
  
  <ul>
  <li>Create two variables instead of one variable; let's call them <code>v[0]</code> and <code>v[1]</code>.</li>
  <li>For each <code>v[i]</code>, create a concurrent dispatch queue for constructing a <a href="http://en.wikipedia.org/wiki/Readers%E2%80%93writer_lock" rel="nofollow">readers-writer-locking</a> mechanism around it. Let's call them <code>q[i]</code>.</li>
  <li>Now for a writing operation, only <code>v[0]</code> gets written to, adhering to the locking mechanism with <code>q[0]</code>.</li>
  <li>On a read operation, at first <code>v[1]</code> is read and only at a certain chance, e.g. 1%, the read operation looks into <code>v[0]</code> and updates <code>v[1]</code> if necessary.</li>
  </ul>
  
  <p>The following pseudo-code illustrates this:</p>
  
  <pre><code>typedef int VType; // the type of the variable
  
  VType* v; // array of first and second variable
  dispatch_queue_t* q; // queues for synchronizing access to v[i]
  
  - (void) setV:(VType)newV {
      [self setV:newV at:0];
  }
  
  - (void) setV:(VType)newV at:(int)i {
      dispatch_barrier_async(q[i], ^{
          v[i] = newV;
      });
  }
  
  - (VType) getV:(int)i {
      __block VType result;
  
      dispatch_sync(q[i], ^{
          result = v[i];
      });
  
      return result;
  }
  
  - (VType) getV {
      VType result = [self getV:1];
  
      if ([self random] &lt; 0.01) {
          VType v0_result = [self getV:0];
  
          if (v0_result != result) {
              [self setV:v0_result at:1];
              result = v0_result;
          }
      }
  
      return result;
  }
  
  - (float) random {
      // some random number generator - fast, but not necessarily good
  }
  </code></pre>
  
  <p>This has the following benefits:</p>
  
  <ul>
  <li><p><code>v[0]</code> is usually not occupied with a read operation. Therefor, a write operation usually does not block.</p></li>
  <li><p>At most times, <code>v[1]</code> does not get written to, thus read operations on this one usually don't block.</p></li>
  <li><p>Still, if many read operations occur, eventually the written values are propagated from <code>v[0]</code> into <code>v[1]</code>. Some values might be missed, but that doesn't matter for my application.</p></li>
  </ul>
  
  <p>What do you guys think, does this work? Are there better solutions?</p>
  
  <p><strong>UPDATE:</strong></p>
  
  <p>Some performance benchmarking (reads and writes of one benchmark at a time are done as quickly as possible concurrently for 1 second, one reading queue, one writing queue):</p>
  
  <p>On iPhone 4S with iOS 7:</p>
  
  <pre><code>runMissingSyncBenchmark: 484759 w/s
  runMissingSyncBenchmark: 489558 r/s
  runConcurrentQueueRWSyncBenchmark: 2303 w/s
  runConcurrentQueueRWSyncBenchmark: 2303 r/s
  runAtomicPropertyBenchmark: 460479 w/s
  runAtomicPropertyBenchmark: 462145 r/s
  </code></pre>
  
  <p>In Simulator with iOS 7:</p>
  
  <pre><code>runMissingSyncBenchmark: 16303208 w/s
  runMissingSyncBenchmark: 12239070 r/s
  runConcurrentQueueRWSyncBenchmark: 2616 w/s
  runConcurrentQueueRWSyncBenchmark: 2615 r/s
  runAtomicPropertyBenchmark: 4212703 w/s
  runAtomicPropertyBenchmark: 4300656 r/s
  </code></pre>
  
  <p>So far, atomic property wins. Tremendously. This was tested with an <code>SInt64</code>.</p>
  
  <p>I expected that the approach with the concurrent queue is similar in performance to the atomic property, as it is the standard approach for an r/w-sync mechanism.</p>
  
  <p>Of course, the <code>runMissingSyncBenchmark</code> sometimes produces reads which show that a write of the <code>SInt64</code> is halfway done.</p>