Example using Interlocked CompareExchange with retry support.
using System.Threading;
using System.Threading.Tasks;
namespace MyProgram
{
class Program
{
static int Main(string[] args)
{
int returnCode = 0;
ThreadSafeParallelOperations();
return returnCode;
}
private static double total = 0.00;
private static void ThreadSafeParallelOperations()
{
Parallel.For(0, 10000, next =>
{
// grab the snapshot
double current = total;
System.Console.WriteLine(
"iteration snapshot (current/total): {0}/{1}", current, total);
// make first attempt...
if (!current.AlmostEquals(
Interlocked.CompareExchange(ref total, current + next, current), 0.0000001))
{
System.Console.WriteLine(
"current value changed since last snapshot (current/total): {0}/{1}",
current, total);
// if we fail, go into a spin wait, spin,
// and try again until succeed
var spinner = new SpinWait();
do
{
spinner.SpinOnce();
current = total;
System.Console.WriteLine(
"a spin occured (current/total): {0}/{1}",
current, total);
}
while (!current.AlmostEquals(
Interlocked.CompareExchange(ref total, current + next, current), 0.0000001)
);
}
});
System.Console.WriteLine("{0}", total);
}
}
public static class Extensions
{
/// <summary>
/// Safely compare doubles for eqaulity.
/// </summary>
/// <returns><c>true</c>, if equals was almosted, <c>false</c> otherwise.</returns>
/// <param name="double1">Double1.</param>
/// <param name="double2">Double2.</param>
/// <param name="precision">Precision.</param>
/// <remarks>
/// Is it safe to check floating point values for equality to 0?:
/// https://stackoverflow.com/a/485777</remarks>
public static bool AlmostEquals(this double double1, double double2, double precision)
{
return (Math.Abs(double1 - double2) <= precision);
}
}
}