Java-подобная синхронизация потоков в C #
-
06-07-2019 - |
Вопрос
Я программист на Java и знаю несколько вещей о многопоточности в Java.
В Java я могу заблокировать метод с помощью синхронизированного ключевого слова:
private int a;
private int b;
private int c;
private synchronized void changeVars()
{
a = 4;
b = 2;
c = a+b;
}
Я искал в msdn и увидел, что в c # есть несколько игрушек для игры с потоками. Например, monitor.Enter, monitor.Exit, блокировка или расширенный мьютекс.
Но мне нужно синхронизировать один метод. Что эквивалентно этому в c #?
Заранее спасибо.
Решение
Что-то вроде этого, возможно,
using System.Runtime.CompilerServices;
...
private int a;
private int b;
private int c;
[MethodImpl(MethodImplOptions.Synchronized)]
private void changeVars()
{
a = 4;
b = 2;
c = a+b;
}
Другие советы
В C # нет прямого эквивалента, но вы можете сделать то же самое с этим:
private readonly object changeVarsLockObject = new object();
private void changeVars()
{
lock(changeVarsLockObject)
{
a = 4;
b = 2;
c = a+b;
}
}
Просто чтобы прояснить: объявление метода, синхронизированного в Java, требует, чтобы вызывающая сторона удерживала монитор на объекте , к которому был вызван метод (который является объектом Class
для статических методов).
То есть вы можете "заблокировать метод" вводит в заблуждение, поскольку вы не полностью блокируете этот метод (один и тот же метод все еще может быть вызван для разных объектов экземпляра), и вы блокируете больше , чем этот метод (никакой другой бит кода, который не требует целевого объекта Монитор, включая другие синхронизированные методы или явные приобретения, может работать одновременно).
Синхронизация сложная , и в идеале вам нужно знать больше, чем " несколько вещей " Об этом, если вы хотите избежать взаимоблокировок и проблем с видимостью, которые почти никогда не появляются во время тестирования или способствуют отладке. Принятие, возможно, неполного понимания синхронизации на одном языке и попытка перенести ее на другой язык с другими примитивами и, вероятно, с другой моделью памяти - это путь к катастрофе.
Итак, хотя это не тот однострочный ответ, который вы искали, я собираюсь утверждать, что любой однострочный ответ обречен на провал без знания всей экосистемы, подкрепляющего его. Таким образом, вы должны прочитать хорошую книгу / учебное пособие по синхронизации в C #, а не пытаться переводить ваш опыт Java по ключевым словам.
Прямой эквивалент этого - использование блокировки (this):
private void ChangeVars()
{
lock (this) {
a = 4;
b = 2;
c = a+b;
}
}
или действительно с использованием MethodImplAttribute, как описано R. Bemrose, что равносильно тому же:
[MethodImpl(MethodImplOptions.Synchronized)]
private void ChangeVars()
{
a = 4;
b = 2;
c = a+b;
}
... однако, не рекомендуется использовать публично видимый объект для блокировки, так как кто-то другой может решить использовать его также как объект блокировки, так что лучшим переводом будет:
private object monitor = new object();
private void ChangeVars()
{
lock (monitor) {
a = 4;
b = 2;
c = a+b;
}
}
Предпочтительное решение - заключить тело метода в оператор lock
.
internal class Foo
{
private Object lockObject = new Object();
private void ChangeVars()
{
lock (this.lockObject)
{
// Manipulate the state.
}
}
}
Вы также можете использовать декларативную синхронизацию, но у этого есть очевидный недостаток, который вы должны извлечь из ContextBoundObject
и все методы, оформленные с помощью Synchronization
совместно используют один и тот же объект блокировки, ограничивая степень детализации блокировки.
internal class Foo : ContextBoundObject
{
[Synchronization]
private void ChangeVars()
{
// Manipulate the state.
}
}