Vì bạn không có khối catch, không có đảm bảo rằng cuối cùng sẽ được thực hiện. Từ MSDN - try-finally (C# Reference) và "Locks and exceptions do not mix" (Eric Lippert)
Trong trường hợp ngoại lệ được xử lý, khối cuối cùng được liên kết được đảm bảo để chạy. Tuy nhiên, nếu ngoại lệ không được giải quyết, việc thực thi khối cuối cùng phụ thuộc vào cách hoạt động ngoại lệ được giải phóng là kích hoạt. Điều đó, đến lượt nó, phụ thuộc vào cách máy tính của bạn được thiết lập.
Và từ liên kết sau đó được đề cập (Unhandled Exception Processing In The CLR) thì có nhiều cân nhắc khác nhau có thể có nghĩa là bạn kết thúc bằng chuỗi bị chấm dứt. Tôi không thành thật biết nếu điều đó sẽ để lại cho bạn một khóa trên đối tượng khóa mặc dù.
Nếu bạn muốn đảm bảo rằng:
- bạn phát hành các khóa; nhưng
- bạn không muốn để xử lý các ngoại lệ ở cấp độ này, thay vào đó bạn muốn nó xử lý bởi một bộ xử lý ngoại lệ mức độ cao hơn
Sau đó làm:
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;
}
Nhưng, xin lưu ý: don Không sử dụng catch (Exception)
để ẩn ngoại lệ, đây chỉ là ok nếu bạn đang ném lại ngoại lệ. Mọi người cũng khuyên bạn nên có một tuyên bố return
duy nhất và thường điều này sẽ nằm ngoài khối thử của bạn.
EDIT:
Xác nhận với một chương trình kiểm tra, và từ MSDN - Exceptions in Managed Threads
Bắt đầu với phiên bản .NET Framework 2.0, ngôn ngữ chung runtime cho phép hầu hết các trường hợp ngoại lệ unhandled trong chủ đề để tiến hành một cách tự nhiên. Trong hầu hết các trường hợp, điều này có nghĩa là ngoại lệ không được xử lý khiến ứng dụng chấm dứt.
Vì vậy, nếu bạn không xử lý ngoại lệ, ứng dụng của bạn sẽ bị lỗi (và bạn sẽ không phải lo lắng về khóa). Nếu bạn xử lý nó, sau đó mã ban đầu của bạn sẽ thực thi nó cuối cùng là khối và bạn là ok.
EDIT 2: Mã Kiểm tra cập nhật vì nó không đúng cách minh họa cho một tổ chức phi bắn cuối cùng:
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);
}
}
}
Đây chỉ là cách khó để viết câu lệnh ** khóa **. Nó là nếu không vô ích để đảm bảo rằng chỉ có một quá trình có thể sử dụng SqlLite, bạn sẽ cần phải sử dụng một Mutex được đặt tên thay thế. –