STAThread và đa luồng


102

Từ bài báo MSDN trên STAThread:

Chỉ ra rằng mô hình phân luồng COM cho một ứng dụng là căn hộ đơn luồng (STA).

(Để tham khảo, đó là toàn bộ bài viết .)

Căn hộ đơn luồng ... OK, điều đó đã qua đầu tôi. Ngoài ra, tôi đã đọc ở đâu đó rằng trừ khi ứng dụng của bạn sử dụng COM interop, thuộc tính này thực sự không làm gì cả. Vậy chính xác thì nó làm gì và ảnh hưởng như thế nào đến các ứng dụng đa luồng? Các ứng dụng đa luồng (bao gồm bất kỳ thứ gì từ bất kỳ ai sử dụng Timers đến các cuộc gọi phương thức không đồng bộ, không chỉ các luồng và tương tự) có nên sử dụng MTAThread không, ngay cả khi nó 'chỉ để an toàn'? STAThread và MTAThread thực sự làm gì?

Câu trả lời:


60

Phân luồng căn hộ là một khái niệm COM; nếu bạn không sử dụng COM và không có API nào mà bạn gọi là sử dụng COM "ở dưới", thì bạn không cần phải lo lắng về căn hộ.

Nếu bạn cần phải biết về căn hộ, thì các chi tiết có thể phức tạp một chút ; một phiên bản có lẽ quá đơn giản là các đối tượng COM được gắn thẻ là STA phải được chạy trên một STAThread và các đối tượng COM được đánh dấu là MTA phải được chạy trên một chuỗi MTA. Sử dụng các quy tắc này, COM có thể tối ưu hóa các cuộc gọi giữa các đối tượng khác nhau này, tránh việc sắp xếp ngẫu nhiên ở những nơi không cần thiết.


7
Đó là đơn giản hóa quá mức. Các đối tượng đa luồng có thể chạy trong bất kỳ luồng nào. Các đối tượng theo chuỗi trong căn hộ chỉ có thể chạy trong căn hộ mà chúng đã được tạo ra.
1800 INFORMATION

28
Một lệnh gọi từ một đối tượng STA trên một luồng STA, đến một đối tượng MTA, sẽ chuyển sang một luồng MTA (trừ khi đối tượng MTA triển khai trình điều phối luồng tự do). Như tôi đã nói, các chi tiết có thể trở nên phức tạp. (Tôi đã làm việc trong nhóm COM trong nhiều năm cười toe toét )
Bruce

9
Đôi khi bạn cần lưu ý điều này ngay cả khi bạn không sử dụng COM trực tiếp. Một luồng phải sử dụng mô hình Căn hộ một luồng nếu nó hiển thị bất kỳ cửa sổ đồ họa nào. Đây là lý do tại sao [STAThread] luôn được hiển thị trên đầu phương thức chính trong ứng dụng biểu mẫu windows.
Justin Ethier

6
Chẳng hạn như hộp thoại Phông chữ hoặc Tệp có thể sử dụng COM mà bạn không biết? Tôi cho rằng họ thực hiện nội bộ, điều đó có nghĩa là hầu hết mọi ứng dụng Windows Forms đều yêu cầu phải đặt STAThread? Hãy tha thứ cho giả định naieve của tôi vì tôi chưa thực sự lập trình COM.
Brett Ryan

4
Một câu trả lời chi tiết hơn cho những người quan tâm: stackoverflow.com/questions/4154429/apartmentstate-for-dummies
jgauffin

3

Nó đảm bảo cái gì CoInitializeđược gọi là chỉ định COINIT_APARTMENTTHREADED làm tham số. Nếu bạn không sử dụng bất kỳ thành phần COM hoặc điều khiển ActiveX nào, nó sẽ không ảnh hưởng gì đến bạn cả. Nếu bạn làm vậy thì đó là điều tối quan trọng.

Các điều khiển theo luồng căn hộ là một luồng hiệu quả, các lệnh gọi đến chúng chỉ có thể được xử lý trong căn hộ mà chúng được tạo ra.

Một số chi tiết khác từ MSDN:

Các đối tượng được tạo trong căn hộ đơn luồng (STA) chỉ nhận các cuộc gọi phương thức từ luồng của căn hộ của chúng, vì vậy các cuộc gọi được tuần tự hóa và chỉ đến ranh giới hàng đợi tin nhắn (khi hàm Win32 PeekMessage hoặc SendMessage được gọi).

Các đối tượng được tạo trên luồng COM trong căn hộ đa luồng (MTA) phải có thể nhận các lệnh gọi phương thức từ các luồng khác bất kỳ lúc nào. Thông thường, bạn sẽ triển khai một số hình thức điều khiển đồng thời trong mã của đối tượng đa luồng bằng cách sử dụng các nguyên thủy đồng bộ hóa Win32 như các phần quan trọng, semaphores hoặc mutexes để giúp bảo vệ dữ liệu của đối tượng.

Khi một đối tượng được cấu hình để chạy trong căn hộ luồng trung tính (NTA) được gọi bởi một luồng nằm trong STA hoặc MTA, luồng đó sẽ chuyển tới NTA. Nếu chuỗi này sau đó gọi CoInitializeEx, thì cuộc gọi không thành công và trả về RPC_E_CHANGED_MODE.


Bài viết MSDN hữu ích từ góc độ COM nhưng bạn có thể cho tôi biết khi nào .NET gọi CoInitialize()đáp lại STAThreadthuộc tính / ApartmentStatekhông? Lưu ý: Bài viết trên MSDN ở đây: Hàm CoInitializeEx .
jrh

Liệu thread-> SetApartment sử dụng CoInitialize()trong nội bộ? Tôi đã lần theo Thuộc tính STAThread xuống đó nhưng đường mòn đã trở nên nguội lạnh (tôi không thể tìm thấy nguồn cho Thread::SetApartment). Lớp Thread từ thread.h (COM thread.h) có được ghi lại ở bất kỳ đâu không? Đó có phải là MFC, ATL hay thứ gì khác không?
jrh

@jrh Tôi không biết chi tiết hơn điều đó xin lỗi
1800 INFORMATION

-15

STAThread được viết trước chức năng Chính của Dự án C # GUI. Nó không làm gì khác ngoài cho phép chương trình tạo một luồng duy nhất.

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.