AutoResetEvent, ManualResetEvent vs Monitor
Предположим, что мне нужно организовать алгоритм синхронизации в .Net 3.5 SP1 и любой из примитивов синхронизации, перечисленных в названии, идеально подходит для задачи.
С точки зрения производительности, есть ли один из тех, кто более результативен, чем другие?
Я спрашиваю об этом, потому что я уже некоторое время кодирую, но без надлежащего знания по этому вопросу.
Ответы
Ответ 1
Если вы можете, зайдите в Monitor. Это похоже на CRITICAL_SECTION. AutoResetEvent/ManualResetEvent может иметь немного больше накладных расходов, поскольку они могут использоваться разными процессами, тогда как монитор принадлежит к одному процессу.
Ответ 2
WaitHandles выглядят очень похожими на Wait/Pulse Constructs, но разница в деталях: метод WaitHandles Set устанавливает Сигнал, даже если нить не ждет. Это означает, что если вы вызываете Set в потоке и затем вызываете WaitOne в другой поток на том же waithandle, то второй поток будет продолжен. Wait и Pulse различны, Pulse только сигнализирует поток, который уже находится в очереди ожидания. Это означает, что если вы вызовете Pulse в потоке, а затем вызовите Wait в другой поток на том же объекте, второй поток будет ждать вечно (deadlock). Вы должны быть предельно осторожны, если используете Wait and Pulse, используйте его только в том случае, если знаете, что делаете, иначе вам просто повезет...
Чтобы создать поведение WaitHandle самостоятельно с помощью Monitor, погоды AutoReset или ManualReset, вам нужно сделать больше, чем просто Wait/Pulse Construct. Просто используйте Инструменты, необходимые для выполнения задания:
Если вы не можете синхронизировать потоки с помощью простых операций блокировки или атома, подумайте об использовании WaitHandles. Если вы не можете синхронизировать потоки с WaitHandles, подумайте об использовании Wait и Pulse.
Ответ 3
Ожидание и пульс в порядке, если вы выполните несколько простых правил:
- Вы можете не заморачиваться, если блокировка не нужна для вашего объекта, и вы можете заранее сказать, что она готова; если, однако, похоже, вам придется подождать, вы должны приобрести блокировку, а затем убедитесь, что вам все еще нужно подождать, прежде чем вы это сделаете; вы также должны в большинстве случаев предполагать, что вас могут случайно разбудить, готовы ли условия, поэтому вы должны перепроверять условия каждый раз, когда вы просыпаетесь, и повторно ждите, если это необходимо.
- Должен быть задан импульс после условий, которые позволят продолжить выполнение кода ожидания.
- Если у вас есть что-то вроде флага "quit", может быть полезно иметь каждый фрагмент кода, который получает проверку блокировки после завершения блокировки и, если флаг установлен, повторно закройте замок и отправьте импульс. Тогда у вас может быть процедура quit, которая устанавливает флаг, попытаться получить блокировку с нулевым таймаутом и отправить импульс только в том случае, если блокировка может быть получена. Если приобретение не удалось, вы можете быть уверены, что какой-то другой фрагмент кода отправит необходимый импульс. Это позволит избежать любой возможности "захода" в процедуру застревания в замке.