Чому потрібен резервний об'єкт блокування?

З цікавості дивився на ключове слово lock на MSDN:

class Account
{
    decimal balance;
    private Object thisLock = new Object();

    public void Withdraw(decimal amount)
    {
        lock (thisLock)
        {
            if (amount > balance)
            {
                throw new Exception("Insufficient funds");
            }
            balance -= amount;
        }
    }
}

У наведеному вище прикладі ключове слово lock використовується об'єкт thisLock . Чому це потрібно? Здається, це не має ніякої іншої мети. Чому б не мати лише ключове слово lock ?

4
@ ChrisSinclair ваша відповідь дає мені те, що я шукав. Дякую.
додано Автор sprocket12, джерело
@ ChrisSinclair ваша відповідь дає мені те, що я шукав. Дякую.
додано Автор sprocket12, джерело
Ключ замків для себе буде недійсним C #. Ви думаєте про lock (this) {...} ?
додано Автор Jon Skeet, джерело
Подумайте про блокування lock як про блокування дверей. Які двері заблоковано? це актуальне запитання, ні?
додано Автор Eric Lippert, джерело
Подумайте про блокування lock як про блокування дверей. Які двері заблоковано? це актуальне запитання, ні?
додано Автор Eric Lippert, джерело
Я думаю, теоретично , мова C #/компілятор може дозволити синтаксис типу lock() , який оброблятиме унікальний об'єкт для це особливий замок Але виникне кілька питань щодо юзабіліту, наприклад: чи є рівень блокування static або instance ? Не кажучи про це, надзвичайно легко випадково не поділяти замки, де ви випадково поставили lock() замість lock (mySharedSyncObject) . Простіше уникнути цього, і просто покладіть на нас необхідність застосувати наш замок намір .
додано Автор Chris Sinclair, джерело
Я думаю, теоретично , мова C #/компілятор може дозволити синтаксис типу lock() , який оброблятиме унікальний об'єкт для це особливий замок Але виникне кілька питань щодо юзабіліту, наприклад: чи є рівень блокування static або instance ? Не кажучи про це, надзвичайно легко випадково не поділяти замки, де ви випадково поставили lock() замість lock (mySharedSyncObject) . Простіше уникнути цього, і просто покладіть на нас необхідність застосувати наш замок намір .
додано Автор Chris Sinclair, джерело

6 Відповіді

lock keyword cannot exist on it's own, it always takes a parameter which will act as a semaphore (synchronizing object), allowing only one thread to proceed.

http://www.albahari.com/threading/part2.aspx#_Locking

Тільки один потік може блокувати об'єкт синхронізації (у цьому випадку   цеLock) одночасно, і будь-які суперечливі нитки блокуються, доки не буде знятий замок. Якщо більше, ніж один потік підтримує замок, вони є   в черзі на "готовій черзі" і надала замок на перший прийом,   на перший погляд (застереження це ті нюанси в поведінці   Windows і CLR означають, що справедливість черги може іноді   бути порушено).

4
додано
Так, ясно, що це якийсь окремий еталон, але я просто збентежений, тому що чому ця функція в мові потрібна розробнику для створення об'єкта для роботи, коли він може бути автоматичним/вбудованим? Тож я думав, може бути, це було більше.
додано Автор sprocket12, джерело
Наприклад, перегляньте вихідний код ConcurrentDictionary , для кожного розділу таблиці використовується окремий об'єкт блокування. Це дозволяє одночасний доступ до словника (навіть при видаленні та додаванні об'єктів), якщо ці звернення відбуваються в різних розділах таблиці. Спільний доступ до об'єкта, який блокує, означає, що за один раз може статися лише одна операція.
додано Автор Brian, джерело
@MuhammadA Це робить припущення, що коли-небудь окреме твердження lock у класі, буде використовувати той самий об'єкт для блокування. Це помилкове припущення. Хоча це, мабуть, найпоширеніша операція, досить часто зустрічаються різні об'єкти, які ви блокуєте (або динамічно, або статично). Ось що робить lock дуже гнучким.
додано Автор Servy, джерело

lock keyword cannot exist on it's own, it always takes a parameter which will act as a semaphore (synchronizing object), allowing only one thread to proceed.

http://www.albahari.com/threading/part2.aspx#_Locking

Тільки один потік може блокувати об'єкт синхронізації (у цьому випадку   цеLock) одночасно, і будь-які суперечливі нитки блокуються, доки не буде знятий замок. Якщо більше, ніж один потік підтримує замок, вони є   в черзі на "готовій черзі" і надала замок на перший прийом,   на перший погляд (застереження це ті нюанси в поведінці   Windows і CLR означають, що справедливість черги може іноді   бути порушено).

4
додано
Так, ясно, що це якийсь окремий еталон, але я просто збентежений, тому що чому ця функція в мові потрібна розробнику для створення об'єкта для роботи, коли він може бути автоматичним/вбудованим? Тож я думав, може бути, це було більше.
додано Автор sprocket12, джерело
Наприклад, перегляньте вихідний код ConcurrentDictionary , для кожного розділу таблиці використовується окремий об'єкт блокування. Це дозволяє одночасний доступ до словника (навіть при видаленні та додаванні об'єктів), якщо ці звернення відбуваються в різних розділах таблиці. Спільний доступ до об'єкта, який блокує, означає, що за один раз може статися лише одна операція.
додано Автор Brian, джерело
@MuhammadA Це робить припущення, що коли-небудь окреме твердження lock у класі, буде використовувати той самий об'єкт для блокування. Це помилкове припущення. Хоча це, мабуть, найпоширеніша операція, досить часто зустрічаються різні об'єкти, які ви блокуєте (або динамічно, або статично). Ось що робить lock дуже гнучким.
додано Автор Servy, джерело

Тут є кілька аспектів:

  • Для операторів lock потрібна посилання на об'єкт як ідентифікатор. Вона повинна мати щось, що ідентифікує цей замок і відокремлює його від будь-яких інших замків, які можуть існувати в коді.

  • Дані, які ви захищаєте, не є еталонним типом, тому вам потрібно щось інше використовувати як ідентифікатор для блокування.

  • Рекомендовано мати приватний об'єкт, який використовується лише як ідентифікатор для блокування, навіть якщо ці дані можна буде використовувати як ідентифікатор. Таким чином, немає ніяких причин, щоб будь-коли висвітлювати довідник за межами класу, оскільки це відкрило б можливі тупикові місця, якщо воно використовувалося в замках за межами класу.

0
додано

Тут є кілька аспектів:

  • Для операторів lock потрібна посилання на об'єкт як ідентифікатор. Вона повинна мати щось, що ідентифікує цей замок і відокремлює його від будь-яких інших замків, які можуть існувати в коді.

  • Дані, які ви захищаєте, не є еталонним типом, тому вам потрібно щось інше використовувати як ідентифікатор для блокування.

  • Рекомендовано мати приватний об'єкт, який використовується лише як ідентифікатор для блокування, навіть якщо ці дані можна буде використовувати як ідентифікатор. Таким чином, немає ніяких причин, щоб будь-коли висвітлювати довідник за межами класу, оскільки це відкрило б можливі тупикові місця, якщо воно використовувалося в замках за межами класу.

0
додано

Об'єкт, який використовується для блокування, не є зайвим. Об'єкт виступає в ролі токену, який використовується для реалізації простого протоколу синхронізації: Хто має замок, він отримує доступ до заблокованого коду. Всі інші повинні зачекати, доки не вийде замок.

Без об'єкта не було б можливо мати різні токени, і вся синхронізація базуватиметься на одному внутрішньому токені. Це не буде дуже ефективним.

0
додано

Об'єкт, який використовується для блокування, не є зайвим. Об'єкт виступає в ролі токену, який використовується для реалізації простого протоколу синхронізації: Хто має замок, він отримує доступ до заблокованого коду. Всі інші повинні зачекати, доки не вийде замок.

Без об'єкта не було б можливо мати різні токени, і вся синхронізація базуватиметься на одному внутрішньому токені. Це не буде дуже ефективним.

0
додано
var chat = new Chat();
var chat = new Chat();
642 учасників

Обсуждение вопросов по C# / .NET / .NET Core / .NET Standard / Azure Сообщества-организаторы: — @itkpi — @dncuug