Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p><code>List&lt;double&gt;</code> is definitely not thread-safe. See the section "thread safety" in the <a href="http://msdn.microsoft.com/en-us/library/6sh2ey19.aspx" rel="nofollow noreferrer">System.Collections.Generic.List documentation</a>. The reason is performance: adding thread safety is not free.</p> <p>Your random number implementation also isn't thread-safe; getting the same numbers multiple times is exactly what you'd expect in this case. Let's use the following simplified model of <code>rnd.NextUniform()</code> to understand what is happening:</p> <ol> <li>calculate pseudo-random number from the current state of the object</li> <li>update state of the object so the next call yields a different number</li> <li>return the pseudo-random number</li> </ol> <p>Now, if two threads execute this method in parallel, something like this may happen:</p> <ul> <li>Thread A calculates a random number as in step 1.</li> <li>Thread B calculates a random number as in step 1. Thread A has not yet updated the state of the object, so the result is the same.</li> <li>Thread A updates the state of the object as in step 2.</li> <li>Thread B updates the state of the object as in step 2, trampling over A's state changes or maybe giving the same result.</li> </ul> <p>As you can see, any reasoning you can do to prove that <code>rnd.NextUniform()</code> works is no longer valid because two threads are interfering with each other. Worse, bugs like this depend on timing and may appear only rarely as "glitches" under certain workloads or on certain systems. Debugging nightmare!</p> <p>One possible solution is to eliminate the state sharing: give <strong>each task its own random number generator</strong> initialized with another seed (assuming that instances are not sharing state through static fields in some way).</p> <p>Another (inferior) solution is to create a field holding <strong>a lock object</strong> in your <code>MersenneTwister</code> class like this: </p> <pre><code>private object lockObject = new object(); </code></pre> <p>Then use this lock in your <code>MersenneTwister.NextUniform()</code> implementation:</p> <pre><code>public double NextUniform() { lock(lockObject) { // original code here } } </code></pre> <p>This will prevent two threads from executing the NextUniform() method in parallel. The problem with the list in your <code>Parallel.For</code> can be addressed in a similar manner: separate the <code>Simulate</code> call and the <code>AddRange</code> call, and then add locking around the <code>AddRange</code> call.</p> <p>My recommendation: avoid sharing any mutable state (like the RNG state) between parallel tasks if at all possible. If no mutable state is shared, no threading issues occur. This also avoids locking bottlenecks: you don't want your "parallel" tasks to wait on a single random number generator that doesn't work in parallel at all. Especially if 30% of the time is spend acquiring random numbers.</p> <p>Limit state sharing and locking to places where you can't avoid it, like when aggregating the results of parallel execution (as in your <code>AddRange</code> calls).</p>
 

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