17

How long is a single spin in c#? What I want to know is there is a ManualResetEventSlim that has a spinCount parameter and I want to know how long each spin is in milliseconds or how it works? I know spinning is more efficient for short waits than a kernel wait. So I am just trying to see what I should set this value to for a job that generally takes 2-10 sec.

user1270384
  • 711
  • 7
  • 24
  • 53
kyleb
  • 1,968
  • 7
  • 31
  • 53

2 Answers2

34

There is no correlation between spinCount parameter in the constructor and the number of milliseconds spent doing a spin wait.

Here is how it works. MRES uses this spinCount parameter to go through its own waiting routine independent of Thread.SpinWait.

  • The first 10 iterations alternate between calling Thread.Yield and Thread.SpinWait. The call to Thread.SpinWait starts with a spin of Environment.ProcessorCount * 4 and then approximately doubles on each successive call.
  • Thereafter each iteration divisible by 20 calls Thread.Sleep(1).
  • Otherwise those divisible by 5 call Thread.Sleep(0).
  • Otherwise Thread.Yield is called.
  • The CancellationToken is checked every 10 iterations after 100.

So as you can see there is a fairly complex song-and-dance going on inside MRES's custom spinning routine. And the algorithm could change from version to version. There is really no way to predict how long each spin will last.

If your typical wait times are 2-10 seconds then your code is almost certainly going to do a kernel level wait via Monitor.Wait and Monitor.Pulse coordinations because the spinCount parameter is limited to 2047 anyway.

Plus, 2-10 seconds is a long time. Do you really want to spin that long?

Brian Gideon
  • 47,849
  • 13
  • 107
  • 150
  • 1
    +1 for interesting details. It tries really hard to get the other thread to release the lock! – Martin James Apr 24 '12 at 20:52
  • Post away, as long as you don't expect me to answer it I would like to know too. On the odd occasions that I've used sleep(0)/sleep(1), (debugging only), I've seen no difference in performance. – Martin James Apr 24 '12 at 21:17
  • @Gabe - it doubles on iteration 1,2,3,4,7,8,9. It does a Yield instead of a SpinWait on iteration 5. On iteration 6 it increases *4. – hatchet - done with SOverflow Apr 24 '12 at 22:48
  • I kinda get it but not completely but whatever I will spin for 10 cycles and let it do kernel mutex. – kyleb Apr 24 '12 at 23:30
  • @Gabe: Yeah, hatchet is right. I said "approximately" because the formula was `ProcessorCount * (4 << iteration)` but the iterations are not necessarily sequential. By the way, there is some pretty thick code in there. I'd like to know how Microsoft came up with that. – Brian Gideon Apr 25 '12 at 01:53
  • @MartinJames: No need for me to post that question. [Someone else](http://stackoverflow.com/q/1413630/158779) beat me to it a long time ago. – Brian Gideon May 02 '12 at 01:49
13

Spin count is meant to be small. The default is 10 (or 1 if running on a single processor). If you use the constructor that lets you specify the spin count, the max allowed is 2047. If the event is not signaled very quickly, the ManualResetEventSlim uses a regular event handle wait. As @HenkHolterman mentioned, the times involved are far, far more tiny than seconds. We're talking cycles, not seconds or even milliseconds.

http://msdn.microsoft.com/en-us/library/5hbefs30.aspx

In the .NET Framework version 4, you can use the System.Threading.ManualResetEventSlim class for better performance when wait times are expected to be very short, and when the event does not cross a process boundary. ManualResetEventSlim uses busy spinning for a short time while it waits for the event to become signaled. When wait times are short, spinning can be much less expensive than waiting by using wait handles. However, if the event does not become signaled within a certain period of time, ManualResetEventSlim resorts to a regular event handle wait.

http://msdn.microsoft.com/en-us/library/ee722114.aspx

On multicore computers, when a resource is not expected to be held for long periods of time, it can be more efficient for a waiting thread to spin in user mode for a few dozen or a few hundred cycles, and then retry to acquire the resource. If the resource is available after spinning, then you have saved several thousand cycles. If the resource is still not available, then you have spent only a few cycles and can still enter a kernel-based wait.

EDIT: To answer your question directly though, the length of time for a single spin cannot be answered definitively, because it depends upon the hardware on which it's running. http://msdn.microsoft.com/en-us/library/system.threading.thread.spinwait(v=vs.95).aspx

SpinWait essentially puts the processor into a very tight loop, with the loop count specified by the iterations parameter. The duration of the wait therefore depends on the speed of the processor.