public static void Lock(ref int lockIndex) {
  for (;;) {
    if (System.Threading.Interlocked.Exchange(ref lockIndex, 1) == 0) {
      break;
    }
  }
}

public static void Unlock(ref int lockIndex) {
  System.Threading.Interlocked.Exchange(ref lockIndex, 0);
}

Мы заводим int поле и используем его в качестве идентификатора для операции блокирования. Другими словами, пока не будет вызван Unlock, второй поток не пройдет через Lock. 

Из минусов такого подхода - если ваш код между этими вызовами упадет по исключению, то все ожидающие потоки повиснут. Для этого я написал дополнение, которое выходит из цикла с ошибкой, если мы ждем слишком долго. 

Как я писал выше в одном из постов, лучше вообще избегать блокировки и Interlocked, но в редких случаях без них не обойтись.

Read More