Если у вас есть набор файлов, которые вы всегда будете проверять, вы можете псевдонимы их путей, например:
alias fd='find . -type f -regex ".*\.\(inc\|info\|module\|php\|test\|install\|uninstall\)"'
Затем вы можете просто отфильтровать список следующим образом:
grep -U -l $'\015' $(fd)
Отфильтровывает список fd для файлов, содержащих шаблон CR.
Я нахожу, что наложение файлов, которые меня интересуют, помогает мне создавать более простые скрипты, а затем всегда пытается вспомнить, как получить все эти файлы. Рекурсивный материал работает, но рано или поздно вам придется бороться с отсечением определенных типов файлов. Именно поэтому я просто нахожу все типы файлов, которые мне интересны для начала.
В документации объясняется (в разделе «Замечания»), что существует концептуальная разница между экземпляром объекта Mutex (который делает не , фактически, делать что-либо особенное насколько синхронизация идет) и получение Mutex (с использованием WaitOne
). Обратите внимание, что:
WaitOne
возвращает логическое значение, что означает, что получение Mutex может сбой (время ожидания), и оба случая должны быть обработаны WaitOne
возвращает true
, тогда вызывающий поток приобрел Mutex и должен вызывать ReleaseMutex
, иначе Mutex перестанет false
], то вызывающий поток не должен вызывать ReleaseMutex
Итак, для мьютексов больше, чем для создания экземпляра. Что касается того, следует ли использовать using
в любом случае, давайте посмотрим, что делает Dispose
(поскольку унаследовано от WaitHandle
):
protected virtual void Dispose(bool explicitDisposing)
{
if (this.safeWaitHandle != null)
{
this.safeWaitHandle.Close();
}
}
Как мы можем см., Mutex выпущен не , но есть какая-то очистка, поэтому прилипание с using
было бы хорошим подходом.
Что касается того, как вы должны действовать, вы можете конечно, используйте блок try/finally
, чтобы убедиться, что, если Mutex получен, что он правильно выпущен. Это, вероятно, самый простой подход.
Если вы действительно не заботятся о случае, когда Mutex не может быть приобретен (что вы не указали, поскольку вы проходите мимо a TimeSpan
- WaitOne
), вы можете обернуть Mutex
в свой класс, который реализует IDisposable
, получить Mutex в конструкторе (используя WaitOne()
без аргументов) и выпустить его внутри Dispose
. Хотя, я бы, вероятно, не рекомендовал бы это, так как это заставило бы ваши потоки ждать бесконечно, если что-то пойдет не так, и независимо от того, есть веские причины для явной обработки обоих случаев при попытке приобретения, как упомянуто @HansPassant.
Dispose
зависит от выхода WaitHandle
. Таким образом, хотя using
вызывает Dispose
, он не будет вдаваться в силу до тех пор, пока не будут выполнены условия стабильного состояния. Когда вы вызываете ReleaseMutex
, вы сообщаете системе, что вы освобождаете ресурс, и, таким образом, он может свободно распоряжаться им.
Это дизайнерское решение было принято давно, давным-давно. Более 21 года назад, задолго до появления .NET, или когда-либо рассматривалась семантика IDisposable. Класс .NET Mutex является классом обертки для базовой поддержки операционной системы для мьютексов. Конструктор pinvokes CreateMutex , метод WaitOne () pinvokes WaitForSingleObject () .
Обратите внимание на возвращаемое WAIT_ABANDONED значение WaitForSingleObject (), это тот, который генерирует исключение.
Дизайнеры Windows поместили твердое правило, в котором поток, который владеет мьютексом, должен вызывать ReleaseMutex () до его выхода. И если это не значит, что это очень сильное указание на то, что поток неожиданно завершен, как правило, через исключение. Это означает, что синхронизация потеряна, очень серьезная проблема с потоками. Сравните с Thread.Abort (), очень опасным способом прервать поток в .NET по той же причине.
Разработчики .NET никоим образом не изменяли это поведение. Не в последнюю очередь потому, что нет никакого способа проверить состояние мьютекса, кроме как выполнить ожидание. Вы должны вызывать ReleaseMutex (). И обратите внимание, что ваш второй фрагмент не является правильным; вы не можете называть это мьютексом, который вы не получили. Он должен быть перемещен внутри тела оператора if ().
+1
- Спасибо за историю! Можете ли вы прокомментировать код, который я разместил в моем ответе i>, на этот вопрос? Из того, что я могу сказать, это должен быть идеальный способ сделать это.
– Mike Christensen
21 August 2014 в 19:44
WaitOne
вызывает также крах?
– Mike Christensen
21 August 2014 в 20:05
WaitXXX
, было изменением с 1.1 до 2.0. В разделе 1.1 (и 1.0) обертки метода WaitXXX
только что вернулись, если они столкнулись с оставленным мьютексом. И много развлечений и игр.
– Damien_The_Unbeliever
22 August 2014 в 07:18
Monitor.Pulse
можно сделать только после приобретения блокировки, но должен быть механизм, посредством которого код, который выключает услугу, может устанавливать свои мониторы на «выключение», без необходимости приобретать связанные блокировки. Если что-то вроде финализатора ...
– supercat
22 August 2014 в 17:12
Нам нужно понять, что больше .net, чтобы знать, что происходит в начале страницы MSDN, дает первый намек на то, что кто-то «нечетно» происходит:
Примитив синхронизации, который также может использоваться для межпроцессной синхронизации.
blockquote>Mutex - это «Именованный объект» Win32, каждый процесс блокирует его по имени, объект .net - это всего лишь оболочка вокруг вызовов Win32. Сам Muxtex живет в адресном пространстве Windows Kernal, а не в адресном пространстве вашего приложения.
В большинстве случаев вам лучше использовать монитор , если вы только пытаетесь синхронизировать доступ к объектам в рамках одного процесса.
Если вам нужно гарантировать, что мьютекс выпущен, переключитесь на блок finally try catch и поместите релиз мьютекса в блок finally. Предполагается, что вы владеете и имеете ручку для мьютекса. Эта логика должна быть включена до вызова release.
using
отличается от try/finally{Dispose()}
?
– Sriram Sakthivel
21 August 2014 в 18:57
try/finally
для вызова ReleaseMutex
, а не только Dispose
(что делается с помощью инструкции using).
– CMircea
21 August 2014 в 19:00
WaitOne
истекает.
– Mike Christensen
21 August 2014 в 19:30
Хорошо, отправляя ответ на мой собственный вопрос. Из того, что я могу сказать, , этот является идеальным способом реализации Mutex
, который:
WaitOne
был успешным. Надеюсь, это поможет кому-то!
using (Mutex mut = new Mutex(false, MUTEX_NAME))
{
if (mut.WaitOne(new TimeSpan(0, 0, 30)))
{
try
{
// Some code that deals with a specific TCP port
// Don't want this to run twice in multiple processes
}
catch(Exception)
{
// Handle exceptions and clean up state
}
finally
{
mut.ReleaseMutex();
}
}
}
Обновление. Некоторые могут утверждать, что если код в блоке try
помещает ваш ресурс в нестабильное состояние, вы должны not отпустить Mutex и вместо этого оставить его заброшенным. Другими словами, просто позвоните mut.ReleaseMutex();
, когда код завершится успешно, а не поместите его в блок finally
. Код, приобретающий Mutex, мог бы поймать это исключение, а сделать правильную вещь .
В моей ситуации я не изменяю какое-либо состояние. Я временно использую TCP-порт и не могу одновременно запускать другой экземпляр программы. По этой причине, я думаю, что мое решение выше, но ваше мнение может быть другим.
catch
после вашего комментария. Но не блок try / finally, без catch(){}
, хорошо: исключение может обрабатываться выше стека, а не проглотить? (И если его вообще не поймать, программа завершается, и не имеет значения, выпуская мьютекс!)
– Darren Cook
20 November 2014 в 12:03
Одно из основных применений мьютекса - гарантировать, что единственный код, который когда-либо увидит общий объект в состоянии, не удовлетворяющем его инвариантам, - это код, который (надеюсь, временно) помещает объект в это состояние. Нормальный шаблон для кода, который должен изменить объект:
Если что-то пошло не так после того, как №2 началось и до того, как №3 закончил, объект может быть оставлен в состоянии, которое не удовлетворяет его инвариантам. Поскольку правильный шаблон заключается в том, чтобы освободить мьютекс перед его удалением, тот факт, что код предоставляет мьютекс, не выпуская его, означает, что что-то пошло не так. Таким образом, может быть небезопасно вводить код в мьютекс (поскольку он не был выпущен), но нет причин ждать выхода мьютекса (поскольку - если он был удален - он никогда не будет) , Таким образом, правильный ход действий - это исключение.
Шаблон, который несколько лучше, чем тот, который реализован объектом mutex .NET, заключается в том, чтобы метод «приобретать» возвращал объект IDisposable
который инкапсулирует не мьютекс, а скорее его частное приобретение. Утилизация этого объекта приведет к отмене мьютекса. Код может выглядеть примерно так:
using(acq = myMutex.Acquire())
{
... stuff that examines but doesn't modify the guarded resource
acq.EnterDanger();
... actions which might invalidate the guarded resource
... actions which make it valid again
acq.LeaveDanger();
... possibly more stuff that examines but doesn't modify the resource
}
Если внутренний код не работает между EnterDanger
и LeaveDanger
, тогда объект сбора должен аннулировать мьютекс, вызывая Dispose
на нем, поскольку охраняемый ресурс может находиться в поврежденном состоянии. Если внутренний код выходит из строя в другом месте, мьютекс должен быть освобожден, поскольку охраняемый ресурс находится в допустимом состоянии, а код в блоке using
больше не понадобится. У меня нет каких-либо конкретных рекомендаций библиотек, реализующих этот шаблон, но это не особенно сложно реализовать в качестве обертки вокруг других видов мьютексов.
Читая документацию для ReleaseMutex
, кажется, что конструктивное решение заключалось в том, что Mutex следует освобождать сознательно. если ReleaseMutex
не вызывается, это означает аномальный выход защищенной секции. сдача релиза в конечном итоге или уничтожение, обходит этот механизм. вы по-прежнему можете игнорировать исключение AbandonedMutex, конечно.
Знайте: Mutex.Dispose (), выполняемый сборщиком мусора, терпит неудачу, потому что процесс сбора мусора не принадлежит дескриптору в соответствии с Windows.
+1
- Отличный ответ! Я думаю, что тот факт, что вы не можете i> вызыватьReleaseMutex
, еслиWaitOne
failed, означает, чтоDispose
не может i> реализовать это, если только он не реализовал логику для отслеживания успешных ожиданий , Похоже, решение состоит в том, чтобы поместитьMutex
в блок использования и поместить блокtry/finally
в блокif
. – Mike Christensen 21 August 2014 в 19:20throw
в случае, если ему не удалось получить мьютекс в своем тайм-ауте, что в любом случае имеет смысл ИМО, поскольку это указывает на сбой. – Benjamin Gruenbaum 15 September 2014 в 09:42