Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Edit: Anyone coming across this, I encourage you to take a look at the discussion. The point about the reader thread modifying the objects in the array-list is very important to this whole class of questions about shared collections (and also why in this case I'd probably go with "just put a big lock on the whole thing" rather than the approach I give here without detailed analysis of those modifications. Still, the following can still work with some cases:</p> <hr> <p>For the pattern of reads to writes that you describe, I would do the following.</p> <p>Let's say the ArrayList is called <code>al</code>. For all reads, I would (mostly, see below) just read from ignoring all thread safety (don't worry, there's method in my madness). To write I would do:</p> <pre><code>ArrayList temp = new ArrayList(al);//create copy of al /* code to update temp goes here */ al = temp;//atomic overwrite of al. Thread.MemoryBarrier();//make sure next read of al isn't moved by compiler or from stale cache value. </code></pre> <p>The copying of <code>al</code> is safe, because ArrayList is safe for multiple readers. The assignment is safe because we're overwriting the reference, which is atomic. We just need to make sure there's a memory barrier though we could probably skip that in practice with most current system (don't though, theoretically at least it's required and let's not second-guess that).</p> <p>This would be pretty dreadful for most shared use of an arraylist, because it makes the writes much more expensive than they have to be. However, those are as you say 60,000,000 times less frequent than the reads, so in this case that balance makes sense.</p> <p>Note on safe reading with this approach:</p> <p>I had made a false assumption because of thinking about a similar case. The following is safe:</p> <pre><code>for(object obj in al) DoSomething(obj); </code></pre> <p>Even when <code>DoSomething</code> could take a long time. The reason is, that this calls <code>GetEnumerator()</code> once and then works on an enumerator that will keep relating to the same list even if <code>al</code> changes in the meantime (it'll be stale, but safe).</p> <p>The following is not safe:</p> <pre><code>for(int i = 0; i &lt; al.Count; ++i) DoSomething(al[i]);// </code></pre> <p><code>Count</code> is safe, but it could be stale by the time you get to <code>al[i]</code> which could mean that you call <code>al[43]</code> when <code>al</code> has only 20 items.</p> <p>It's also safe to call <code>BinarySearch</code>, <code>Clone</code>, <code>Contains</code>, <code>IndexOf</code> and <code>GetRange</code>, but not safe to use the results of <code>BinarySearch</code>, <code>Contains</code> or <code>IndexOf</code> to decide upon a second thing you do with <code>al</code> because it could have changed by that time.</p> <p>The following is also safe:</p> <pre><code>ArrayList list = al; for(int i = 0; i != list.Count; ++i) DoSomething(list[i]); DoSomethingElse(list); DoSomethingReallyComplicated(list); for(int i = 0; i != list.Count; ++i) SureWhyNotLetsLoopAgain(list[i]); </code></pre> <p>Note that we are not copying <code>al</code>, just copying the reference, so this is really really cheap. Everything we do with <code>list</code> is safe, because if it become stale, it's still one thread's own version of the old list and can't go wrong.</p> <p>So. Either do everything in a <code>foreach</code> (the case I was mistakenly assuming), return the results of a single call to the methods noted as safe above (but don't use it to decide whether to do another operation on <code>al</code>), or assign <code>al</code> to a local variable and act on that.</p> <hr> <p>Another <strong>really</strong> important caveat, is whether the writer thread will actually set any properties or call any non-threadsafe methods on any of the objects contained in the arraylist. If it does, then you've gone from having one thread synchronisation issue to think about, to having dozens!</p> <p>If this is the case, then you have to worry about not just the arraylist, but each object that can be changed (by changed I mean the way calling <code>.Append("abc")</code> on a <code>StringBuilder</code> changes that object, not replacing with a completely new object the way <code>str = "abc"</code> changes <code>str</code>).</p> <p>There are four safe possibilities:</p> <ol> <li>You have immutable objects in your arraylist - happy days.</li> <li>You have mutable objects, but don't mutate them - good too, but you have to be <em>sure</em>.</li> <li>You have threadsafe objects - okay, but that does mean you've at least one set of threading problems that is more complicated than the one this question deals with.</li> <li>You lock on each object for both writing and reading - while locks being contested is less likely with such fine locks, this has its own heaviness and really you're no better than the default (and it should be the default) answer of "just lock, locks are cheap when not contested anyway).</li> </ol>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload