2010-11-11 28 views
88

Tôi chỉ sửa một lỗi sử dụng này:ApartmentState cho núm vú cao su

_Thread.SetApartmentState(ApartmentState.STA); 

Bây giờ tôi muốn hiểu rõ ý nghĩa của nó, và tại sao nó hoạt động!

+1

Bài đăng [This] (http://stackoverflow.com/questions/165316/stathread-and-multithreading) có thể giúp bạn –

Trả lời

178

COM là cha đẻ của .NET. Họ có những mục tiêu cao cả với nó, một trong những điều mà COM làm nhưng .NET bỏ qua hoàn toàn là cung cấp sự đảm bảo luồng cho một lớp. Một lớp COM có thể xuất bản những loại yêu cầu luồng mà nó có. Và cơ sở hạ tầng COM đảm bảo rằng các yêu cầu đó được đáp ứng.

Điều này hoàn toàn không có trong .NET. Bạn có thể sử dụng một đối tượng Queue <> ví dụ trong nhiều chủ đề nhưng nếu bạn không khóa đúng cách, bạn sẽ có một lỗi khó chịu trong mã của bạn rất khó chẩn đoán.

Chi tiết chính xác của luồng COM quá lớn để vừa với bài đăng. Tôi sẽ tập trung vào các chi tiết cụ thể của câu hỏi của bạn. Một chủ đề tạo ra các đối tượng COM phải cho COM biết loại hỗ trợ nào mà nó muốn cung cấp cho các lớp COM có các tùy chọn luồng hạn chế. Phần lớn các lớp đó chỉ hỗ trợ cái gọi là Luồng căn hộ, các phương thức giao diện của chúng chỉ có thể được gọi một cách an toàn từ cùng một luồng đã tạo ra cá thể đó. Nói cách khác, họ thông báo "Tôi không hỗ trợ luồng nào, hãy chăm sóc không bao giờ gọi cho tôi từ chuỗi không đúng". Ngay cả khi mã máy khách thực sự là thì hãy gọi gọi nó từ một chuỗi khác.

Có hai loại, STA (Single Threaded Apartment) và MTA. Nó được xác định trong cuộc gọi CoInitializeEx(), một hàm phải được gọi bởi bất kỳ luồng nào làm bất cứ điều gì với COM. CLR thực hiện cuộc gọi đó tự động bất cứ khi nào nó bắt đầu một chuỗi. Đối với chuỗi khởi động chính của chương trình, nó nhận giá trị để chuyển từ thuộc tính [STAThread] hoặc [MTAThread] trên phương thức Main() của bạn. Mặc định là MTA. Đối với các chủ đề mà bạn tự tạo, nó được xác định bằng lời gọi của bạn tới SetApartmentState(). Mặc định là MTA. Threadpool thread luôn luôn MTA, mà không thể thay đổi.

Có nhiều mã trong Windows yêu cầu STA. Các ví dụ đáng chú ý là các hộp thoại Clipboard, Drag + Drop và các hộp thoại vỏ (như OpenFileDialog). Chuỗi giao diện người dùng của dự án WPF hoặc Windows Forms phải luôn là STA, cũng như bất kỳ chuỗi nào tạo cửa sổ.

Lời hứa bạn thực hiện với COM rằng chuỗi của bạn là STA tuy nhiên không yêu cầu bạn tuân theo hợp đồng căn hộ một sợi. Họ là khá cứng và bạn có thể nhận được khá khó khăn để chẩn đoán rắc rối khi bạn phá vỡ hợp đồng. Yêu cầu là bạn không bao giờ chặn luồng cho bất kỳ khoảng thời gian nào và bạn bơm vòng lặp tin nhắn. Yêu cầu thứ hai được đáp ứng bởi một chuỗi giao diện người dùng của WPF hoặc Winforms nhưng bạn sẽ cần tự chăm sóc nó nếu bạn tạo chuỗi STA của riêng bạn. Chẩn đoán chung để phá vỡ hợp đồng là bế tắc.

Có khá nhiều hỗ trợ tích hợp trong CLR để hỗ trợ các yêu cầu này, giúp bạn tránh rắc rối. Ví dụ: tuyên bố khóa sẽ bơm vòng lặp tin nhắn khi nó chặn trên chuỗi STA. Hầu hết các lớp đồng bộ hóa làm tốt, Mutex là một ngoại lệ đáng chú ý. Tuy nhiên, điều này chỉ đảm bảo yêu cầu không bao giờ chặn, bạn vẫn cần tạo vòng lặp tin nhắn của riêng mình. Application.Run() trong cả WPF và Winforms.

Trước đây tôi đã đóng góp câu trả lời chứa nhiều chi tiết hơn về ý nghĩa của việc có vòng lặp tin nhắn để giữ COM hài lòng. Bạn sẽ tìm thấy số post here.

+2

Câu trả lời hay! Lỗi mà tôi đã giải quyết là một chuỗi mà tôi đã tạo cho một trình tạo báo cáo chạy dài sử dụng các điều khiển WPF để tạo các phần của báo cáo, do đó, điều đó có ý nghĩa, mặc dù tôi không biết rằng luồng đó có vòng lặp thông báo trên đó . – Benjol

+1

Tôi nghiêm túc phải đọc bài MSDN nhiều lần để hiểu nó, Câu trả lời của bạn rất rõ ràng và được viết tốt. Cảm ơn bạn! – ak3nat0n

+4

phản hồi này hoàn toàn và tuyệt vời. –

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