-#if NET_4_0
// SpinWait.cs
//
// Copyright (c) 2008 Jérémie "Garuma" Laval
//
//
+#if NET_4_0
using System;
namespace System.Threading
{
-
public struct SpinWait
{
// The number of step until SpinOnce yield on multicore machine
const int step = 10;
+ const int maxTime = 200;
static readonly bool isSingleCpu = (Environment.ProcessorCount == 1);
-
+
int ntime;
-
- public void SpinOnce()
+
+ public void SpinOnce ()
{
- // On a single-CPU system, spinning does no good
+ ntime += 1;
+
if (isSingleCpu) {
- Yield();
+ // On a single-CPU system, spinning does no good
+ Thread.Yield ();
} else {
- if (Interlocked.Increment(ref ntime) % step == 0) {
- Yield();
- } else {
+ if (ntime % step == 0)
+ Thread.Yield ();
+ else
// Multi-CPU system might be hyper-threaded, let other thread run
- Thread.SpinWait(10);
- }
+ Thread.SpinWait (Math.Min (ntime, maxTime) << 1);
}
}
-
- void Yield()
+
+ public static void SpinUntil (Func<bool> condition)
+ {
+ SpinWait sw = new SpinWait ();
+ while (!condition ())
+ sw.SpinOnce ();
+ }
+
+ public static bool SpinUntil (Func<bool> condition, TimeSpan timeout)
+ {
+ return SpinUntil (condition, (int)timeout.TotalMilliseconds);
+ }
+
+ public static bool SpinUntil (Func<bool> condition, int millisecondsTimeout)
{
- // Replace sched_yield by Thread.Sleep(0) which does almost the same thing
- // (going back in kernel mode and yielding) but avoid the branching and unmanaged bridge
- Thread.Sleep(0);
+ SpinWait sw = new SpinWait ();
+ Watch watch = Watch.StartNew ();
+
+ while (!condition ()) {
+ if (watch.ElapsedMilliseconds > millisecondsTimeout)
+ return false;
+ sw.SpinOnce ();
+ }
+
+ return true;
}
-
- public void Reset()
+
+ public void Reset ()
{
ntime = 0;
}
-
+
public bool NextSpinWillYield {
get {
return isSingleCpu ? true : ntime % step == 0;
}
}
-
+
public int Count {
get {
return ntime;