Поскольку у вас нет блока catch, нет гарантии, что, наконец, он будет выполнен. От MSDN - try-finally (C# Reference) и "Locks and exceptions do not mix" (Eric Lippert)
В течение перекачиваемой исключения, связанный с ним, наконец, блок гарантированно для запуска. Тем не менее, , если исключение необработанно, выполнение окончательного блока зависит от того, как выполняется операция разблокировки исключения , вызванное. Это, в свою очередь, зависит от того, как настроен ваш компьютер.
И из упомянутой ссылки (Unhandled Exception Processing In The CLR) существуют различные соображения, которые могут означать, что вы закончите с завершенной нитью. Я честно не знаю, может ли это оставить вас с блокировкой на объекте блокировки.
Если вы хотите, чтобы убедиться, что:
- отпускании замок; но
- вы не хотите, чтобы обработать исключение на этом уровне, а вы хотите, обрабатываются обработчиком исключений выше уровня
Затем сделайте:
TheXmlType xml = null;
Monitor.Enter(Lock);
bool inLock = true;
try {
...
xml = filter.Xml; // put this here in case it throws an exception
inLock = false; // set this here in case monitor.exit is to
// throw an exception so we don't do the same all over again in the catch block
Monitor.Exit(Lock);
return xml; // this is fine here, but i would normally put it outside my try
}
catch (Exception) {
if (inLock) Monitor.Exit(Lock);
throw;
}
Но, обратите внимание: дон 't использовать catch (Exception)
, чтобы скрыть исключения, это нормально, если вы повторно выбрасываете исключение. Люди также рекомендуют вам иметь один оператор return
, и обычно это будет за пределами блока try.
EDIT:
Подтвержденные с программой испытаний, и от MSDN - Exceptions in Managed Threads
Начиная с .NET Framework версии 2.0, общий язык среда позволяет большинству необработанных исключений в резьб для продолжения естественно. В большинстве случаев это означает, что необработанное исключение заставляет приложение завершать работу.
Таким образом, если вы не справитесь со своим исключением, ваше приложение потерпит крах (и вам не придется беспокоиться о блокировке). Если вы справитесь с этим, ваш исходный код выполнит его, наконец, блок, и вы в порядке.
EDIT 2: Код Test обновляется, поскольку он не должным образом иллюстрируют негор наконец:
class Program
{
static void Main(string[] args) {
Program p =new Program();
p.Start();
Console.WriteLine("done, press enter to finish");
Console.ReadLine();
}
private readonly object SyncRoot = new object();
ManualResetEvent mre = new ManualResetEvent(false);
private void Start() {
/*
* The application will run the thread, which throws an exception
* While Windows kicks in to deal with it and terminate the app, we still get
* a couple of "Failed to lock" messages
* */
Thread t1 = new Thread(SetLockAndTerminate);
t1.Start();
mre.WaitOne();
for (int i = 0; i < 10; i++) {
if (!Monitor.TryEnter(this.SyncRoot, 1000)) {
Console.WriteLine("Failed to lock");
}
else {
Console.WriteLine("lock succeeded");
return;
}
}
Console.WriteLine("FINALLY NOT CALLED");
}
public int CauseAnOverflow(int i)
{
return CauseAnOverflow(i + 1);
}
public void SetLockAndTerminate() {
Monitor.Enter(this.SyncRoot);
Console.WriteLine("Entered");
try {
mre.Set();
CauseAnOverflow(1); // Cause a stack overflow, prevents finally firing
}
finally {
Console.WriteLine("Exiting");
Monitor.Exit(this.SyncRoot);
}
}
}
Это просто трудный способ написать инструкцию ** lock **. В противном случае бесполезно гарантировать, что только один процесс может использовать SqlLite, вместо этого вам нужно будет использовать именованный Mutex. –