Căn hộ dành cho người giả


118

Tôi vừa sửa một lỗi bằng cách sử dụng này:

_Thread.SetApartmentState(ApartmentState.STA);

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


1
Bài đăng này có thể giúp bạn
Arsen Mkrtchyan

Câu trả lời:


234

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

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

Các chi tiết chính xác của luồng COM quá lớn để phù hợp với bài viết. Tôi sẽ tập trung vào chi tiết cụ thể của câu hỏi của bạn. Một luồng tạo các đối tượng COM phải cho COM biết loại hỗ trợ nào nó muốn cung cấp cho các lớp COM có các tùy chọn luồng bị hạn chế. Phần lớn các lớp đó chỉ hỗ trợ cái gọi là phân 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 thể hiện. Nói cách khác, họ thông báo "Tôi không hỗ trợ xâu chuỗi bất cứ điều gì, xin vui lòng không bao giờ gọi tôi từ chuỗi sai". Thậm chí nếu các mã khách hàng thực sự không gọi nó là từ thread khác.

Có hai loại, STA (Căn hộ đơn luồng) và MTA. Nó được chỉ định trong lệnh 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 luồng khởi động chính của chương trình của bạn, nó nhận giá trị được truyề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ởi lệnh gọi của bạn tới SetApemonyState (). Mặc định là MTA. Chủ đề Threadpool luôn là MTA, không thể thay đổi.

Có rất nhiều mã trong Windows yêu cầu STA. Các ví dụ đáng chú ý mà bạn sử dụng cho mình là Clipboard, Kéo + Thả và các hộp thoại shell (như OpenFileDialog). Và rất nhiều mã mà bạn không thể nhìn thấy, như các chương trình Tự động hóa và móc nối để quan sát các thông báo. Không có mã nào trong số đó phải an toàn cho luồng, tác giả của nó sẽ có một thời gian rất khó khăn để làm cho nó an toàn mà không biết nó được sử dụng trong chương trình nào. Theo đó, luồng UI của dự án WPF hoặc Windows Forms phải luôn là STA để hỗ trợ mã đó, cũng như bất kỳ luồng nào tạo ra một cửa sổ.

Lời hứa bạn thực hiện cho COM rằng chủ đề của bạn được STA tuy nhiên không yêu cầu bạn phải tuân theo hợp đồng căn hộ một chủ đề. Họ khá cứng và bạn có thể gặp 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 chuỗi trong bất kỳ khoảng thời gian nào và bạn bơm một vòng lặp thông báo. Yêu cầu thứ hai được đáp ứng bởi luồng UI 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 luồng STA của riêng mình. Chẩn đoán phổ biến cho việc 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 btw, giúp bạn tránh khỏi rắc rối. Câu lệnh khóa và các phương thức WaitOne () bơm một vòng lặp thông báo khi nó chặn trên một luồng STA. Điều này tuy nhiên chỉ quan tâm đến 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 một câu trả lời có chứa nhiều chi tiết hơn về tầm quan trọng của việc có một vòng lặp thông báo để giữ cho COM luôn vui vẻ. Bạn sẽ tìm thấy bài viết ở đây .


3
Câu trả lời tuyệt vời! Lỗi mà tôi đã giải quyết là đối với một luồng mà tôi đã tạo cho trình tạo báo cáo chạy dài, sử dụng các điều khiển WPF để xây dựng các phần của báo cáo, vì vậy đ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 đó .
Stewol

3
Tôi thực sự đã phải đọc bài viết 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
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.