2013-02-01 40 views
10

Vì vậy, tôi đã hạnh phúc đọc this từ Eric Lippert và sau đó, tất nhiên, các ý kiến ​​tuyệt vời và trong họ John Payson nói:Tại sao không có bế tắc trong trường hợp này?

một ví dụ thú vị hơn có thể đã sử dụng hai lớp tĩnh, vì như vậy một chương trình có thể bế tắc mà không có bất kỳ câu lệnh chặn hiển thị nào.

và tôi nghĩ, yeah, mà muốn được dễ dàng vì vậy tôi gõ lên này:

public static class A 
{  
    static A() 
    { 
     Console.WriteLine("A.ctor"); 
     B.Initialize(); 
     Console.WriteLine("A.ctor.end"); 
    } 

    public static void Initialize() 
    { 
     Console.WriteLine("A.Initialize"); 
    } 
} 
public static class B 
{ 
    static B() 
    { 
     Console.WriteLine("B.ctor"); 
     A.Initialize(); 
     Console.WriteLine("B.ctor.end"); 
    } 

    public static void Initialize() 
    { 
     Console.WriteLine("B.Initialize"); 
    } 

    public static void Go() 
    { 
     Console.WriteLine("Go"); 
    } 
} 

Kết quả trong số đó (sau khi gọi B.Go()) là:

B.ctor 
A.ctor 
B.Initialize 
A.ctor.end 
A.Initialize 
B.ctor.end 
Go 

Không bế tắc và tôi rõ ràng là kẻ thua cuộc - vì vậy để duy trì sự xấu hổ, đây là câu hỏi của tôi: tại sao không bế tắc ở đây?

Dường như với não nhỏ bé của tôi rằng B.Initialize được gọi trước constructor tĩnh của B đã kết thúc và tôi nghĩ rằng điều đó không được phép.

+0

Có thể sẽ thú vị khi xem stacktraces tại mỗi điểm. – leppie

+0

Làm thế nào để bạn đề xuất bế tắc một chuỗi? Tất cả mọi thứ đang xảy ra đồng bộ ... –

Trả lời

1

Điểm quan trọng là chỉ có một chuỗi liên quan. Trích dẫn từ bài đăng trên blog:

Phương thức khởi tạo tĩnh sau đó khởi động một chuỗi mới. Khi chuỗi đó bắt đầu, CLR thấy rằng một phương thức tĩnh sắp được gọi trên một kiểu có hàm tạo tĩnh là "đang bay" một luồng khác. Nó ngay lập tức chặn luồng mới để phương thức khởi tạo sẽ không bắt đầu cho đến khi luồng chính kết thúc chạy hàm tạo lớp.

Trong ví dụ Erics, có hai luồng đang chờ nhau. Bạn chỉ có một chủ đề, do đó, không có chờ đợi xảy ra và kết quả là: không chặn và không có bế tắc.

+0

Ah, vâng, đó sẽ là lý do tại sao tôi ngu ngốc - tất nhiên tôi không thể bế tắc một chuỗi đơn lẻ - tôi chỉ có thể, như @pickypg đã nói, tạo ra một kịch bản không an toàn. Cảm ơn bạn – kmp

+0

Có rõ ràng khi nào hàm dựng tĩnh được thực hiện trong một luồng mới và khi nó không xảy ra? –

+0

@zespri: Vui lòng cung cấp mẫu. –

0

Các phương pháp tĩnh được gọi chỉ một lần và một khi được tải lại thì không được gọi lại. Nó sẽ là bế tắc nếu phương pháp A.Initialize() được gọi là phương pháp B.Initialize() và ngược lại. Vì vậy, bất kỳ lớp nào được nạp vào bộ nhớ, khối tĩnh được thực hiện và sau đó bất kỳ một lớp nào được gọi đến trước đó - bởi vì lớp đã được nạp để khối tĩnh không được thực hiện.

+0

Nếu A.Initialize gọi là B.Initialize và ngược lại sẽ không gây ra một StackOverflowException, không phải là một bế tắc? – kmp

+0

vì không có tài nguyên chung ở đây mà 2 lớp đang đề cập đến nên không có khái niệm bế tắc - điều duy nhất có thể xảy ra là lấp đầy ngăn xếp. –

+0

Đó rõ ràng là đệ quy nhưng không có bế tắc. –

-3

Ví dụ lớp thực sự được tạo trước khi gọi hàm tạo, do đó không cần thực hiện hàm tạo nữa.

+0

ở đâu chúng ta tạo ra các đối tượng trước hết là inorder để thực hiện các hàm tạo - vì chúng ta chỉ sử dụng các phương thức tĩnh và các khối tĩnh không có khái niệm về các hàm tạo. –

6

Nó không phải là bế tắc bởi vì bạn không làm bất cứ điều gì nên chặn, cũng không phải là bạn làm bất cứ điều gì mà nên phá vỡ.

Bạn không sử dụng bất kỳ tài nguyên nào từ A trong vòng B và ngược lại. Kết quả là, phụ thuộc vòng tròn của bạn là "an toàn" theo nghĩa là không có gì sẽ phát nổ.

Nếu bạn xác định đường đi bản in của bạn hiển thị, sau đó không có gì nên chặn:

  1. Gọi Go (tôi nghi ngờ)
  2. Nhập B (static constructor) vì nó không được khởi tạo.
  3. In ra
  4. Sử dụng A.Initialize()
  5. A 's static constructor được yêu cầu phải thực hiện đầu tiên
  6. In ra
  7. Sử dụng B.Initialize()
  8. B không cần phải khởi tạo, nhưng nó không phải ở trong tình trạng hoàn thành (may mắn là không có biến nào được đặt, vì vậy không có gì xảy ra)
  9. In ra, sau đó quay lại
  10. In ra (từ A 's static constructor), sau đó trở
  11. A.Initialize() cuối cùng có thể được gọi vì A được khởi
  12. In ra ngoài, sau đó trở về
  13. In ra (từ B' s static constructor), sau đó trở lại
  14. Go

điều duy nhất mà bạn thực sự đã có mặt tiềm năng cho một nhà nước không an toàn: truy cập vào một lớp học mà nhà xây dựng không có t thực hiện xong. Đó là mã không an toàn và trong khi không chặn, chắc chắn đại diện cho trạng thái bị hỏng.

1

Tại sao bạn cho rằng nên có bế tắc. Các hàm tạo tĩnh được gọi chỉ một lần. Không có vấn đề bao nhiêu thời gian bạn thực hiện tuyên bố B.Initialize(); nó sẽ gọi constructor tĩnh của lớp B chỉ lần đầu tiên khi B được gọi. Xem thêm về các hàm tạo tĩnh here.

Các vấn đề liên quan