C # версія синхронізованого ключового слова Java?


313

Чи має c # власну версію ключового слова java "синхронізовано"?

Тобто в java його можна вказати або функції, об'єкту або блоку коду, наприклад:

public synchronized void doImportantStuff() {
   // dangerous code goes here.
}

або

public void doImportantStuff() {
   // trivial stuff

   synchronized(someLock) {
      // dangerous code goes here.
   }
}

3
Блокова форма вимагає посилання на блокування. У формі форми об'єктом блокування неявно це (або Клас [this.class, не getClass ()] для статичних методів, але не блокувати на Класи).
Том Хотін - тайклін

1
Ще не захищено? Я завжди приходжу сюди, бо не можу згадати цю [MethodImpl(MethodImplOptions.Synchronized)]лінію.
Bitterblue

1
Я думаю, що ваш другий фрагмент не збирається - його потрібно синхронізувати на чомусь.
PoweredByRice

Відповіді:


466

По-перше - більшість класів ніколи не потребуватимуть безпеки. Використовуйте YAGNI : застосовуйте безпеку різьби лише тоді, коли ви знаєте, що насправді збираєтесь її використовувати (і протестуйте).

Для матеріалів на рівні методу є [MethodImpl]:

[MethodImpl(MethodImplOptions.Synchronized)]
public void SomeMethod() {/* code */}

Це також можна використовувати в аксесуарах (властивості та події):

private int i;
public int SomeProperty
{
    [MethodImpl(MethodImplOptions.Synchronized)]
    get { return i; }
    [MethodImpl(MethodImplOptions.Synchronized)]
    set { i = value; }
}

Зауважте, що події, подібні до поля , синхронізуються за замовчуванням, тоді як властивості, реалізовані автоматично , не :

public int SomeProperty {get;set;} // not synchronized
public event EventHandler SomeEvent; // synchronized

Особисто мені не подобається реалізація, MethodImplоскільки вона блокується thisабо typeof(Foo)- що проти кращої практики. Кращим варіантом є використання власних замків:

private readonly object syncLock = new object();
public void SomeMethod() {
    lock(syncLock) { /* code */ }
}

Зауважте, що для подій, подібних до поля, реалізація блокування залежить від компілятора; у старих компіляторах Microsoft це lock(this)/ lock(Type)- однак, у більш пізніх компіляторах він використовуєInterlocked оновлення - настільки безпечний для потоків без противних частин.

Це дозволяє більш детально використовувати та дозволяє використовувати Monitor.Wait/ Monitor.Pulseetc для зв'язку між потоками.

Пов'язаний запис у блозі (пізніше переглянуто ).


@earcam і твоє питання? Це твердження вірно. Переважна більшість класів не має вимоги бути поточно-, що не буде випробувана для безпеки потоків, і має потокобезпечна впливатиме на продуктивність. Кількість типів, про які справді потрібно турбуватися про нитки, дуже мала - навмисно синхронізовані колекції, мультиплексори тощо
Marc Gravell

4
Я думаю, я повинен був просто заявити; "Більшість класів ніколи не потребуватимуть захисту від потоку", але "всі розробники повинні мати знання" В ретроспективі я погоджуюся, що кількість дуже мала (і, безумовно, щось, що ви хочете отримати один раз в одному місці, що дозволяє більшості класів взаємодіяти, не зважаючи на їх багатопотокове оточення). Бажаю, щоб я видалив коментар швидше =)
earcam

6
Повідомлення про блог, пов’язане з Марком, має подальше повідомлення у березні 2010 року, в якому йдеться про те, що в .NET 4.0 MethodImplта польових подіях зараз генерується хороший код синхронізації, і більше не потрібно використовувати власні блокування.
Rory O'Kane

2
Значна більшість застосувань у наші дні є веб-основою, яка обслуговується рамками, що покладаються на багаторазове повторне використання та складний життєвий цикл об'єкта за допомогою введення залежності. Мислення за замовчуванням в ці дні, як правило, помиляється в сторону безпеки потоку.
Sheepy

1
@Elazar зараз занадто пізно, але для запису: зміна рамки - це зміна одного рядка в csproj, якщо ви створили його за допомогою шаблонів .net стандарт / основні .net. - і звичайний .net доступний, як і багато -націлювання. Однак інструменти IDE навколо цього просто жахливі - вам просто потрібно знати, що ви можете змінити і на що :)
Marc Gravell

57
static object Lock = new object();

lock (Lock) 
{
// do stuff
}

9
Ви впевнені, що хочете оголосити об'єкт блокування статичним ..?
serg10

21
Звичайно, тому кожна тема може легко отримати доступ до неї, не передаючи посилання навколо.
Ян Грессманн

32
Якщо ми знаходимося в контексті питання запитувача, то мова йде про методи екземпляра. Використання статики означає, що якщо потік 1 викликає instance1.DoSomething () і потік 2 викликає instance2.DoSomething, другий виклик блокується, навіть якщо це абсолютно інший об'єкт. Виклик thread2 не повинен блокуватись, якщо хтось не викликає DoSomething на один і той же об'єкт . Не кажучи, що ви помиляєтесь, але кажучи, що важливо зрозуміти ефект використання статики тут, оскільки це може спричинити низьку ефективність, блокуючи глобально, а не на основі примірника.
AaronLS

1
@AaronLS Статичний замок дуже корисний, коли ваш об'єкт виконує дії на більшому обсязі, ніж сам. Завжди, наприклад, з веб-сервісами.
Тібо Д.

3
-1 оскільки це інша поведінка, ніж просить ОП. Це блокування класів, а не блокування екземпляра.
tster

39

Чи має c # власну версію ключового слова java "синхронізовано"?

Ні. У C # ви явно використовуєте lockресурси, над якими ви хочете працювати синхронно в асинхронних потоках. lockвідкриває блок; він не працює на рівні методу.

Однак базовий механізм схожий, оскільки lockпрацює за допомогою виклику Monitor.Enter(і згодом Monitor.Exit) під час виконання. Java працює точно так само, в відповідно до документацією Sun .


3
У нього немає еквівалентного "ключового слова", але як показує відповідь Марка Гравелла вище, ви можете синхронізувати на рівні методу за допомогою анотації [MethodImpl (MethodImplOptions.Synchronized)].
MindJuice

1
Оскільки synchronizedметод методу Java в основному synchronized (this.getClass())не схожий на C # lock(typeof(this))?
Шрі Харша Чілакапаті

2
@SriHarshaChilakapati, що лише частково правильно, synchronizedключове слово Java в методі більше схоже на:, synchronized(this)тільки на статичний метод він поводиться так synchronized(class).
bvdb

7

Візьміть на замітку, з повними стежками лінія: [MethodImpl(MethodImplOptions.Synchronized)]має виглядати

[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.Synchronized)]


1
або ви можете просто скористатисяusing System.Runtime.CompilerServices;
aloisdg, переходячи до codidact.com,

Я написав цей коментар, коли я ще не знав про автоматичне вставлення з використанням операторів, після того, як запрограмував C # не більше кількох днів або тижнів, і я вражений цими 3-ма результатами.
Traubenfuchs

1
Ви допомогли принаймні 3 диски, і це приємно :)
aloisdg переходить на codidact.com

5

Ви можете використовувати lockоператор замість цього. Я думаю, що це може замінити лише другу версію. Також пам’ятайте, що обом synchronizedі lockпотрібно діяти над об’єктом.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.