Синхронизация операций в .NET на примерах

  • lock-object. Это самый простой способ синхронизации. Мы заводим объект, который будем использовать для блокировки параллельного выполнения какого-то участка кода.

    1. Применять стоит, когда нам нужно, чтобы какой-то участок кода в один момент времени выполнялся только одним потоком. Тут может быть любая работа с файлами, БД и другими ресурсами.

    2. Важно понимать, что lock работает на уровне приложения, а не ОС, поэтому другое приложение может спокойно занять наш ресурс.

    3. Еще следует помнить, что код в lock секции должен выполняться в рамках одного потока, поэтому мы не можем использовать внутри асинхронные вызовы.

      Синтаксис
  • Mutex. Используется для ограничения доступа к ресурсу на уровне ОС.

    1. Его может освободить только тот поток, который его занял.

    2. Подойдет для ограничения доступа к файлам.

      Синтаксис
      Синтаксис
  • SemaphoreSlim. Облегченная версия семафора. Сам семафор предоставляется ОС и используется для того, чтобы ограничить число одновременных пользователей ресурса.

    1. Работает на уровне ОС.

    2. Можем указать, сколько одновременно потоков могут работать с ресурсом. Полезно, если мы не хотим перегрузить его, например, при обращении к сетевой карте при REST-запросах.

    3. Слим версия может быть асинхронной, что полезно для работы с файлами, к которым мы хотим ограничить доступ. На работе некоторые настройки сервисов мы храним в .json-файлах, для ограничения доступа к ним из нескольких потоков, мы используем слим версию и асинхронное ожидание.

      Синтаксис
      Синтаксис
  • AutoResetEvent. Как и классы выше служит для синхронизации доступа к ресурсу.

    1. Отличие в том, что позволяет управлять одним потоком из другого.

      Синтаксис
      Синтаксис
  • Interlcoked. Служит для произведения атомарных операций.

    1. Подходит, если есть какая-то переменная, которую мы хотим атомарно изменять.

    2. Еще с его помощью можно поставить флаг на какую-то часть кода, которую должен выполнять какой-то из потоков, но нам не важно какой. Тогда при первом входе в метод поток будет поднимать флаг через Interlocked, а другие потоки будут выходить из метода, когда будут видеть, что флаг уже поднят.

      Пример работы с флагом через Interlocked
      Пример работы с флагом через Interlocked