Tại sao sử dụng thử {} cuối cùng {} với một khối thử trống?


239

Tôi nhận thấy trong System.Threading.TimerBase.Dispose()phương thức có một try{} finally{}khối nhưng try{}trống.

Có bất kỳ giá trị trong việc sử dụng try{} finally{}với một sản phẩm nào trykhông?

http://labs.developerfusion.co.uk/SourceViewer/browse.aspx?assinstall=SSCLI&namespace=System.Threading&type=TimerBase

[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
internal bool Dispose(WaitHandle notifyObject)
{
    bool status = false;
    bool bLockTaken = false;
    RuntimeHelpers.PrepareConstrainedRegions();
    try {
    }
    finally {
        do {
            if (Interlocked.CompareExchange(ref m_lock, 1, 0) == 0) {
                bLockTaken = true;
                try {
                    status = DeleteTimerNative(notifyObject.SafeWaitHandle);
                }
                finally {
                    m_lock = 0;
                }
            }
            Thread.SpinWait(1);
            // yield to processor
        }
        while (!bLockTaken);
        GC.SuppressFinalize(this);
    }

    return status;
}

System.Diagnostics.Process xung quanh dòng 2144 cũng như: referencesource.microsoft.com/#System/services/monitoring/...
Patrick Artner

Câu trả lời:


171

Từ http://blog.somecreativity.com/2008/04/10/the-empty-try-block-mystery/ :

Phương pháp này bảo vệ chống lại một cuộc gọi Thread.Abort làm gián đoạn quá trình xử lý. Trang MSDN của Thread.Abort nói rằng các khối cuối cùng không được thực hiện được thực thi trước khi luồng bị hủy bỏ. Vì vậy, để đảm bảo rằng quá trình xử lý của bạn kết thúc ngay cả khi luồng của bạn bị hủy bỏ ở giữa bởi ai đó gọi Abort trên luồng của bạn, bạn có thể đặt tất cả mã của mình vào khối cuối cùng (cách khác là viết mã trong khối bắt Bắt xác định bạn đã ở đâu trước khi ăn thử, bị gián đoạn bởi Abort và tiếp tục từ đó nếu bạn muốn).



15
Bởi vì điều đó không có sẵn cho đến .NET 2.0
Hans Passant

6
@ RobFonseca-Ensor: Bởi vì Thread.BeginCriticalRegion()không ngăn chặn một luồng bị hủy bỏ, thay vào đó hãy nói với bộ thực thi rằng nếu một luồng bị hủy bỏ, thì trạng thái toàn cầu bị hỏng và toàn bộ tên miền appd bị giết chết.
kkm

9
@HansPassant: BeginCriticalSection()thực sự không có trong .NET 1.x, nhưng không có nguyên nhân và kết quả, mà bạn ngụ ý khi nói bởi vì . Trong thực tế, trong .NET 1.x, ngay cả một finallykhối cũng có thể bị gián đoạn bởi việc hủy bỏ luồng. Các cơ chế này phục vụ một mục đích khác: thực hiện công việc trong việc finallyngăn chặn việc hủy bỏ giữa chừng trong mã, trong khi BeginCriticalSection()chỉ tuyên bố với thời gian chạy rằng trạng thái toàn cầu có nguy cơ.
kkm

Nếu nhà phát triển có một thời gian (đúng) cuối cùng thì việc hủy bỏ sẽ hoàn thành hay việc hủy bỏ về mặt kỹ thuật có thể bị bỏ qua vô thời hạn?
Max Young

64

Điều này là để bảo vệ chống lại Thread.Abortlàm gián đoạn một quá trình. Tài liệu cho phương pháp này nói rằng:

Các khối cuối cùng không được thực hiện trước khi luồng bị hủy bỏ.

Điều này là do để khôi phục thành công từ một lỗi, mã của bạn sẽ cần phải tự dọn sạch. Vì C # không có các hàm hủy kiểu C ++ finallyusingcác khối là cách duy nhất đáng tin cậy để đảm bảo rằng việc dọn dẹp như vậy được thực hiện một cách đáng tin cậy. Hãy nhớ rằng usingkhối biến thành cái này bởi trình biên dịch:

try {
    ...
}
finally {
    if(obj != null)
        ((IDisposable)obj).Dispose();
}

Trong .NET 1.x, có khả năng finallykhối sẽ bị hủy bỏ. Hành vi này đã được thay đổi trong .NET 2.0.

Hơn nữa, trycác khối trống không bao giờ được tối ưu hóa bởi trình biên dịch.


Cảm ơn cho cái nhìn sâu sắc về khối sử dụng.
Stefan

@Anton Tôi hiểu rằng sử dụng là một thực hành tốt nhất. Nhưng với mục đích chế giễu, đôi khi một lớp trình bao bọc cần được thực hiện và đối tượng dùng một lần trở thành một biến lớp riêng. Nếu chúng ta làm cho trình bao bọc này dùng một lần, thì không phải GC sẽ tự động xử lý biến lớp riêng tư sao?
Ozkan

@Ozkan, GC không tự động loại bỏ bất cứ thứ gì. Bạn sẽ cần phải thực hiện một bộ hoàn thiện, thường gọi là a Dispose(false);. docs.microsoft.com/en-us/dotnet/stiteria/garbage-collection/iêu
Thorarin

@Thorarin xin lỗi nhưng bạn đã sai khi nói rằng GC không tự động xử lý (hoàn thiện).
Ozkan
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.