This article mainly explains three ways of.net spinlock based on Thread


## Implement spin lock based on Thread.SpinWait implementation principle: based on Test–And–Set atomic operation, use a data to indicate whether the current lock has been acquired. 0 indicates that the lock is not acquired. 1 indicates that the lock has been obtained. When the lock is obtained, the _lock value is set to 1 and then check whether the value before modification is 0. Advantages:

  • If thread. SpinWait is not used, the retry method will be empty, and the CPU will use its maximum performance to continuously assign and compare instructions, wasting a lot of performance. Thread.SpinWait indicates that the CPU is currently in a spin lock cycle and can rest for several cycles
  • The problem with using a spin lock is that the code protected by a spin lock should be executed in a very short period of time. If the time is too long, other threads will continue to retry, affecting other threads

Disadvantages:

  • The current implementation does not consider fairness. If multiple threads fail to acquire the lock at the same time, the first thread to acquire the lock in chronological order may not be the first thread to acquire the lock after releasing it.

Code implementation:

public static class ThreadSpinWaitDemo { private static int _lock = 0; private static int _counterA = 0; private static int _counterB = 0; public static void IncrementCounters() { while (Interlocked.Exchange(ref _lock, 1) ! = 0) { Thread.SpinWait(1); } ++_counterA; ++_counterB; Interlocked.Exchange(ref _lock, 0); } public static void GetCounters(out int counterA, out int counterB) { while (Interlocked.Exchange(ref _lock, 1) ! = 0) { Thread.SpinWait(1); } counterA = _counterA; counterB = _counterB; Interlocked.Exchange(ref _lock, 0); }}Copy the code

SpinWaite based spinlock implementation

Thread.SpinWait is called if the number of times the SpinOnce method is greater than or equal to 1. Thread.sleep (0) and thread.yield are used alternately to switch to another Thread if the number of cores in the current environment exceeds a certain number of times, or if the number of cores in the current environment equals 1. SpinWaite solves two problems in Thread.SpinWait

  • If the spin lock takes too long, SpinWaite can prompt the operating system to switch to another thread or put the current thread to sleep,
  • SpinWaite does not execute Thread.SpinWait if the current environment has only one core logic. Instead, it prompts the operating system to switch to another Thread.
public static class ThreadSpinOnceDemo { private static int _lock = 0; private static int _counterA = 0; private static int _counterB = 0; public static void IncrementCounters() { var spinWait = new SpinWait(); while (Interlocked.Exchange(ref _lock, 1) ! = 0) { spinWait.SpinOnce(); } ++_counterA; ++_counterB; Interlocked.Exchange(ref _lock, 0); } public static void GetCounters(out int counterA, out int counterB) { var spinWait = new SpinWait(); while (Interlocked.Exchange(ref _lock, 1) ! = 0) { spinWait.SpinOnce(); } counterA = _counterA; counterB = _counterB; Interlocked.Exchange(ref _lock, 0); }}Copy the code

Implement SpinLock based on SpinLock

Encapsulates SpinWaite logic

SpinLock code implementation

public class ThreadSpinLockDemo { private static SpinLock _spinLock = new SpinLock(); private static int _counterA = 0; private static int _counterB = 0; public static void IncrementCounters() { bool lockTaken = false; try { _spinLock.Enter(ref lockTaken); ++_counterA; ++_counterB; } finally { if (lockTaken) { _spinLock.Exit(); } } } public static void GetCounters(out int counterA, out int counterB) { bool lockTaken = false; try { _spinLock.Enter(ref lockTaken); counterA = _counterA; counterB = _counterB; } finally { if (lockTaken) { _spinLock.Exit(); }}}}Copy the code

1. Describe the differences between thread.sleep (0) and thread.yield

  • Sleep calls the SleepEx function, while thread. Yield calls the SwitchToThread method.
  • The SwitchToThread function can only switch to the current core associated thread, not to another core associated thread. The SleepEx function can only switch to the current core associated thread, not to another core associated thread. And keep the current thread from re-entering the queue for a specified amount of time (if the thread is 0, the thread can re-enter the queue immediately).
  • On Linux and OSX, thread. Sleep calls the pthread_cond_timedWait function provided by the Pthread library when the Sleep time is not 0, and sched_yield when the Sleep time is 0. Thread.Yield also calls the sched_yield function. Sched_yield does not differ between Windows and OSX systems in that it switches only to the threads on the runnable queue that the logical core cares about, but not to other threads associated with the core logic. Calling the system-provided sleep function and passing in 0 on a Unix system ignores the return

This article summarizes the basics of.NET Core

Welcome to correct me if I am not very clear or make mistakes

If you like, you might as well click a thumbprint collection 🙂 personal wechat! [](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/7fc3fd25b41b43528500d3b45b8d2973~tplv-k3u1fbpfcp-zoom-1.image)Copy the code