Каковы различия между различными параметрами синхронизации streamов в C #?
Может кто-то объяснить разницу между:
- lock (someobject) {}
- Использование Mutex
- Использование Семафора
- Использование монитора
- Использование других classов синхронизации .Net
Я просто не могу понять. Мне кажется, что первые два одинаковы?
- Синхронизация по целочисленному значению
- Как использовать семафоры между процессами с использованием общей памяти
- Синхронизация IPC с общей памятью (без блокировки)
- Как подождать, пока все горуты не закончатся, не используя время.
- Статический и нестатический объект блокировки в синхронизированном блоке
- Как определить, заблокирован ли объект (синхронизирован), чтобы он не блокировался на Java?
- В чем разница между атомными / летучими / синхронизированными?
- Как синхронизированные статические методы работают на Java?
- Синхронизированный блок Java против Collections.synchronizedMap
- C # версия синхронизированного ключевого слова java?
- Явная блокировка Java
- Монитор против Mutex в c #
- В чем разница между синхронизацией на lockObject и использованием этого как блокировки?
Отличный вопрос. Я, возможно, ошибаюсь .. Позвольте мне попробовать .. Редакция №2 моего ответа на вопрос .. с немного более глубоким пониманием. Спасибо, что заставил меня читать 🙂
Блокировка (OBJ)
- представляет собой конструкцию CLR, которая для синхронизации streamов (внутри объекта?). Обеспечивает, чтобы только один stream мог взять на себя ответственность за блокировку объекта и ввести заблокированный блок кода. Другие streamи должны ждать, пока текущий владелец откажется от блокировки, выходя из блока кода. Также рекомендуется блокировать частный объект-член вашего classа.
Мониторы
- lock (obj) реализуется внутренне с помощью монитора. Вы должны предпочесть блокировку (obj), потому что это мешает вам разобраться, как забыть процедуру очистки. Это «конструкция идиота», если вы это сделаете.
Использование монитора обычно предпочтительнее над мьютексами, поскольку мониторы были разработаны специально для .NET Framework и поэтому лучше используют ресурсы.
Использование блокировки или монитора полезно для предотвращения одновременного выполнения зависящих от streamа блоков кода, но эти конструкции не позволяют одному streamу передавать событие другому. Для этого требуются события синхронизации , которые являются объектами, которые имеют одно из двух состояний, сигнализируются и не сигнализируются, которые могут использоваться для активации и приостановки streamов. Мьютекс, Семафоры – это концепции уровня ОС. например, с именованным мьютеком, который вы могли бы синхронизировать с несколькими (управляемыми) exes (гарантируя, что на компьютере работает только один экземпляр вашего приложения).
мьютекс:
- Однако, в отличие от мониторов, мьютекс может использоваться для синхронизации streamов между процессами. При использовании для межпроцессной синхронизации мьютекс называется именованным мьютеком, потому что он должен использоваться в другом приложении, и поэтому он не может быть разделен с помощью глобальной или статической переменной. Ему должно быть присвоено имя, чтобы оба приложения могли получить доступ к одному и тому же объекту mutex. Напротив, class Mutex является оболочкой для конструкции Win32. Хотя он более мощный, чем монитор, для мьютекса требуются переходы interop, которые являются более вычислительно дорогостоящими, чем те, которые требуются classу Monitor.
Семафоры (повреждают мой мозг).
- Используйте class Semaphore для управления доступом к пулу ресурсов. Потоки входят в семафор, вызывая метод WaitOne, который наследуется от classа WaitHandle, и освобождает семафор, вызывая метод Release. Счетчик на семафоре уменьшается каждый раз, когда stream входит в семафор и увеличивается, когда stream освобождает семафор. Когда счетчик равен нулю, последующие запросы блокируют до тех пор, пока другие streamи не освободят семафор. Когда все streamи освобождают семафор, счетчик имеет максимальное значение, указанное при создании семафора. Поток может входить в семафор несколько раз. Класс Семафор не обеспечивает идентификацию streamов на WaitOne или Release .. ответственность программистов не замалчивается. Семафоры бывают двух типов: локальные семафоры и семафоры с именем system. Если вы создаете объект Semaphore, используя конструктор, который принимает имя, он связан с семафором операционной системы этого имени. Именованные системные семафоры видны во всей операционной системе и могут использоваться для синхронизации действий процессов. Локальный семафор существует только внутри вашего процесса. Он может использоваться любым streamом в вашем процессе, который имеет ссылку на локальный объект Semaphore. Каждый объект Семафор представляет собой отдельный локальный семафор.
СТРАНИЦА ДЛЯ ПРОЧИТАНИЯ – Синхронизация streamов (C #)
Re “Использование других classов синхронизации .Net” – некоторые из других, о которых вы должны знать:
- ReaderWriterLock – позволяет использовать несколько считывателей или одного записывающего устройства (не в одно и то же время)
- ReaderWriterLockSlim – как указано выше, более низкие накладные расходы
- ManualResetEvent – ворота, которые позволяют пропустить код при открытии
- AutoResetEvent – как указано выше, но автоматически отключается после открытия
Кроме того, в CCR / TPL ( Parallel Extensions CTP) есть блокировки с большим количеством накладных расходов, но в IIRC они будут доступны в .NET 4.0
Как указано в ECMA, и, как вы можете наблюдать из Reflected methods, оператор блокировки в основном эквивалентен
object obj = x; System.Threading.Monitor.Enter(obj); try { … } finally { System.Threading.Monitor.Exit(obj); }
Из приведенного выше примера мы видим, что мониторы могут блокировать объекты.
Mutexe полезны, когда вам нужна межпроцессная синхронизация, поскольку они могут блокировать строковый идентификатор. Один и тот же строковый идентификатор может использоваться различными процессами для получения блокировки.
Семафоры подобны мьютексам на стероидах, они позволяют одновременный доступ, обеспечивая максимальное количество одновременного доступа ». Как только предел достигнут, семафор начинает блокировать любой дальнейший доступ к ресурсу, пока один из вызывающих абонентов не выпустит семафор.
Я сделал classы и поддержку CLR для streamовой передачи в DotGNU, и у меня есть несколько соображений …
Если вам не нужны перекрестные блокировки процессов, вы всегда должны избегать использования Mutex & Semaphores. Эти classы в .NET являются обертками вокруг Mutex и Семафоров Win32 и имеют довольно большой вес (для них требуется контекстный переключатель в kernel, которое дорого – особенно, если ваша блокировка не находится под угрозой).
Как упоминалось выше, оператор C # lock – это магия компилятора для Monitor.Enter и Monitor.Exit (существует в try / finally).
У мониторов есть простой, но мощный механизм сигнала / ожидания, который не имеет Mutexes с помощью методов Monitor.Pulse / Monitor.Wait. Эквивалент Win32 будет объектами событий через CreateEvent, которые на самом деле также существуют в .NET как WaitHandles. Модель Pulse / Wait похожа на pthread_signal и pthread_wait от Unix, но быстрее, потому что они могут быть полностью пользовательскими режимами в непротиворечивом случае.
Monitor.Pulse / Wait прост в использовании. В одном streamе мы блокируем объект, проверяем флаг / состояние / свойство, и если это не то, что мы ожидаем, вызовите Monitor.Wait, который отпустит блокировку и дождитесь отправки импульса. Когда ожидание вернется, мы вернемся назад и снова проверим флаг / состояние / свойство. В другом streamе мы блокируем объект всякий раз, когда мы меняем свойство flag / state /, а затем вызываем PulseAll, чтобы разбудить любые прослушивающие streamи.
Часто мы хотим, чтобы наши classы были streamобезопасными, поэтому мы помещаем блокировки в наш код. Однако часто бывает, что наш class будет использоваться только одним streamом. Это означает, что блокировки бесполезно замедляют наш код … именно здесь умная оптимизация в среде CLR может повысить производительность.
Я не уверен в реализации блокировок Microsoft, но в DotGNU и Mono флаг состояния блокировки хранится в заголовке каждого объекта. Каждый объект в .NET (и Java) может стать блокировкой, поэтому каждый объект должен поддерживать это в своем заголовке. В реализации DotGNU существует флаг, который позволяет использовать глобальную hash-таблицу для каждого объекта, который используется как блокировка, – это имеет преимущество устранения 4-байтных служебных данных для каждого объекта. Это не очень удобно для памяти (особенно для встроенных систем, которые не сильно загружены в streamи), но они поражают производительность.
Оба Mono и DotGNU эффективно используют мьютексы для выполнения блокировки / ожидания, но используют операции сравнения и обмена спин-блокированием, чтобы исключить необходимость выполнения жестких блокировок, если это действительно необходимо:
Вы можете увидеть пример того, как мониторы могут быть реализованы здесь:
http://cvs.savannah.gnu.org/viewvc/dotgnu-pnet/pnet/engine/lib_monitor.c?revision=1.7&view=markup
Дополнительное предостережение для блокировки любых общих мьютексов, которые вы идентифицировали с идентификатором строки, заключается в том, что по умолчанию будет использоваться мьютекс «Локальный» и не будет использоваться для сеансов в среде сервера терминалов.
Присвойте свой строковый идентификатор «Global», чтобы обеспечить надлежащий контроль доступа к общим системным ресурсам. Я просто столкнулся с целым кучей проблем, синхронизирующих связь с сервисом, запущенным под учетной записью SYSTEM, прежде чем я это понял.
Я бы постарался избежать «lock ()», «Mutex» и «Monitor», если вы можете …
Проверьте новое пространство имен System.Collections.Concurrent в .NET 4
В нем есть несколько classных classов, не связанных с streamами
http://msdn.microsoft.com/en-us/library/system.collections.concurrent.aspx
ConcurrentDictionary породы! для меня ручная блокировка больше!