Ответ
В оператор lock передаётся объект-маркер (монитор), который используется для синхронизации потоков при доступе к критической секции кода. Этот объект должен быть ссылочного типа.
Критически важные правила выбора объекта:
- Приватный и только для блокировок: Объект должен быть
private(илиprivate staticдля статических методов) и не использоваться для других целей. Это предотвращает внешние взаимоблокировки. - Ссылочный тип: Примитивные типы значений (
int,bool) не подходят. Используйте специально созданный экземплярobject. - Избегайте
this: Использованиеlock(this)— антипаттерн, так как публичный экземпляр класса может быть заблокирован извне. - Избегайте
Typeи строк:lock(typeof(MyClass))опасен из-за глобальности.lock("myLock")опасен из-за интернирования строк — одна литеральная строка во всем приложении будет одним объектом.
Правильный пример:
public class ThreadSafeCounter
{
private int _count = 0;
private readonly object _lockObject = new object(); // Специальный объект для блокировки
public void Increment()
{
lock (_lockObject) // _lockObject выступает маркером для входа в критическую секцию
{
_count++; // Эта операция теперь атомарна для всех потоков
}
}
public int GetCount()
{
lock (_lockObject)
{
return _count;
}
}
}
Альтернативы: Для более сложных сценариев рассмотрите Monitor (который используется внутри lock), Mutex (для межпроцессной синхронизации) или примитивы из пространства имен System.Threading (например, SemaphoreSlim, ReaderWriterLockSlim).
Ответ 18+ 🔞
Слушай, ну вот объясняют же люди, как с этим lock'ом работать, а потом смотришь на код — и волосы дыбом, ёпта! Будто человек впервые слышит, что потоки существуют. Ладно, щас разжую.
Вот смотри, есть у тебя критическая секция — кусок кода, куда нафиг нельзя пускать всех сразу, как в переполненный сортир на рок-фестивале. Чтобы не было давки и говна по стенам, ты ставишь замок. В C# это оператор lock. А в этот lock ты суёшь объект-маркер, он же монитор. Это как ключ от того самого сортира: у кого ключ — тот и делает свои дела, остальные ждут, как лохи, с поджатыми ягодицами.
А теперь, блядь, самое важное — что за объект ты туда пихаешь:
- Делай его приватным и только для этого.
private readonly object _lockObject = new object();— вот твой друг. Не используй эту хуйню больше ни для чего! Иначе какой-нибудь умник из другого класса возьмёт и заблокирует твой же объект, и будет взаимная блокировка, пиздец и deadlock. А ты потом голову ломаешь, почему всё зависло. - Только ссылочный тип, нахуй! Не вздумай пихать
intилиbool— это типы значения, они не катят. Нужен именно объект в куче. - Забудь как страшный сон
lock(this). Это классический распиздяйский приём.this— публичный экземпляр твоего класса. Любой другой код может его заблокировать, и твой поток будет ждать у разбитого корыта. Пидарас тот, кто так делает. - Не используй
typeof(MyClass)и уж тем более строки.lock(typeof(MyClass))— это глобальная блокировка на весь тип, овердохуища проблем. Аlock("myLock")— это вообще пиздец, потому что строки интернируются, и одна и та же строка во всём приложении — один объект. Представь, ты блокируешься по строке "lock", а в соседней библиотеке, о которой ты не знаешь, тоже кто-то по "lock" блокируется. И вы оба ебётесь, не понимая, кто кого держит. Короче, ядрёна вошь.
Вот как надо, по-человечески:
public class ThreadSafeCounter
{
private int _count = 0;
// Вот он, красавец, специально созданный костыль для блокировки
private readonly object _lockObject = new object();
public void Increment()
{
lock (_lockObject) // Захватили ключ
{
_count++; // Сделали дело быстро
} // Освободили ключ — следующий, заходи!
}
public int GetCount()
{
lock (_lockObject)
{
return _count;
}
}
}
Всё, элементарно, Ватсон. Создал объектик, используешь его в lock. Никакой магии.
Если задачи посерьёзнее — там уже можно на Monitor ручками позырить (который внутри lock и работает), или на Mutex для синхронизации между процессами, или на SemaphoreSlim всякий. Но для обычных бытовых случаев lock с правильным объектом — твоя палочка-выручалочка. Главное — не выебывайся и не пытайся быть умнее системы, а то будет тебе хиросима, а не многопоточность.