2010-02-21 43 views
10

Tôi có Biểu mẫu Windows có ListView trong Chế độ báo cáo. Đối với mỗi mục trong dạng xem, tôi cần thực hiện một thao tác chạy dài, kết quả là một số.Tương đương C# của MsgWaitForMultipleObjects là gì?

Cách tôi sẽ làm điều này trong win32 gốc là tạo một chuỗi công nhân cho mỗi mục (ngây thơ; tất nhiên tôi sẽ không tạo số chuỗi không bị chặn) và sau đó MsgWaitForMultipleObjects() trên mảng xử lý chuỗi. Khi mỗi phép tính kết thúc, tín hiệu luồng và chuỗi giao diện người dùng chính sẽ thức dậy và cập nhật. Trong thời gian đó, chúng tôi bơm các thông điệp để chuỗi giao diện người dùng vẫn đáp ứng.

Có ai có thể cung cấp ví dụ về cách thức hoạt động của tính năng này trong C# không? Tôi đã nhìn vào đối tượng Monitor, và nó không có vẻ là những gì tôi muốn - hoặc nó bơm thông điệp trong khi chặn?

Cảm ơn.

Chỉnh sửa: Có vẻ như WaitHandler.WaitAny() thực sự có thể bơm tin nhắn. Xem cbrumme's treatise khi bơm thông báo trong CLR.

+0

Bạn nói đúng, Màn hình không bơm tin nhắn. WaitHandle có thể là một nơi tốt hơn để nhìn, nhưng tôi không thể tìm thấy một phương pháp WaitHandle cũng bơm tin nhắn. – itowlson

+0

Vâng, tôi cũng thấy điều đó. Nó không phải là một yêu cầu hoặc là tôi có thể chờ đợi trên nhiều đối tượng. Tôi sẽ đợi một sự kiện hay một thứ gì đó ... Tôi không muốn chặn giao diện người dùng. Tất cả các mẫu tôi đã tìm thấy làm 'giấc ngủ (100)' hoặc một cái gì đó để buộc một chuyển đổi ngữ cảnh, mà là rất buồn. –

+0

Tôi đoán vấn đề là trong WinForms vòng lặp tin nhắn không rõ ràng. Vì vậy, bạn không thể làm một MsgWaitX trực tiếp, thay vào đó bạn cần một cái gì đó mà sẽ nâng cao một sự kiện. Ví dụ, chạy từng subtask như một BackgroundWorker (và quên đi các nguyên thủy đồng bộ). – itowlson

Trả lời

2

Đối tượng hoạt động dài hạn, tôi nghĩ, là lựa chọn tốt nhất trong trường hợp của bạn. Chủ đề chính gọi proxy (của đối tượng đang hoạt động). Proxy chuyển đổi phương thức cuộc gọi thành tin nhắn và thông báo này sẽ chuyển thành hàng đợi. Proxy trả về cho người gọi đối tượng tương lai (nó là một tham chiếu đến kết quả trong tương lai). Điều phối viên dequeues tin nhắn từng người một và thực sự thực hiện nhiệm vụ của bạn trong thread khác (thread làm việc). Khi thread làm việc hoàn thành một nhiệm vụ, nó cập nhật kết quả của đối tượng tương lai hoặc gọi phương thức gọi lại (ví dụ, để cập nhật giao diện người dùng của bạn) .Dispather có thể có nhiều luồng làm việc để thực hiện nhiều tác vụ cùng một lúc.

Bạn có thể thấy điều này article (có mẫu) về mẫu đối tượng hoạt động dài hạn.

+0

Vui lòng cung cấp một số thông tin và không chỉ liên kết đến thông tin. –

+0

Hmm, điều đó thực sự có vẻ như rất nhiều mã để giải quyết một vấn đề đơn giản như vậy. Ý tôi là, tôi luôn có thể ghim đối tượng COM của riêng mình nếu tôi muốn. Nếu khung công tác C# không đủ chín chắn để tôi làm điều này một cách dễ dàng, tôi có thể quay lại viết mã win32. Mặc dù tôi phải tin rằng họ là một cách dễ dàng để làm điều này. –

+0

Có, bạn đã đúng. Đây là một ví dụ từ MSDN: connection1.Open(); SqlCommand command1 = SqlCommand mới (commandText1, connection1); Kết quả IAsyncResult1 = command1.BeginExecuteNonQuery(); WaitHandle waitHandle1 = result1.AsyncWaitHandle; connection2.Open(); \t \t ... \t \t WaitHandle [] = {waitHandles waitHandle1, waitHandle2, waitHandle3 }; \t \t kết quả bool = WaitHandle.WaitAll (waitHandles, 60000, false); – garik

2

Có chủ đề chính của bạn tạo chuỗi trình quản lý. Bạn có thể sử dụng số BackgroundWorker cho việc này. Chuỗi trình quản lý này khởi tạo chuỗi công việc cho từng mục trong ListView. Điều này sẽ cho phép giao diện người dùng của bạn tiếp tục trả lời người dùng mà không bị treo trong khi các chủ đề nền đang xử lý.

Bây giờ, vấn đề là cách đợi cho mỗi chuỗi công nhân hoàn tất. Thật không may, tôi đã không thể tìm thấy một cách để có được một xử lý thread cho các đối tượng System.Threading.Thread. Tôi không nói rằng không có cách nào để làm điều đó; Tôi chỉ không tìm thấy một. Một khía cạnh phức tạp khác là lớp System.Threading.Thread được niêm phong, vì vậy chúng tôi không thể lấy được từ nó để cung cấp một số loại 'xử lý'.

Đây là nơi tôi sử dụng ManualResetEvent.

Giả sử mỗi chuỗi công nhân chỉ đơn giản là một chuỗi ThreadPool. Việc quản lý BackgroundWorker tạo đối tượng ManualResetEvent cho mỗi mục trong ListView. Khi số BackgroundWorker khởi chạy mỗi chuỗi ThreadPool, hãy chuyển số ManualResetEvent làm đối số cho số QueueUserWorkItem function. Sau đó, ngay trước mỗi lần thoát ThreadPool luồng, đặt đối tượng ManualResetEvent.

Chủ đề BackgroundWorker sau đó có thể đặt tất cả các đối tượng ManualResetEvent vào một mảng và đợi trên mảng đó bằng cách sử dụng WaitHandle.WaitXXX functions. Khi mỗi luồng kết thúc, bạn có thể sử dụng các sự kiện của BackgroundWorker để cập nhật giao diện người dùng hoặc bạn có thể sử dụng kỹ thuật Control.Invoke() để cập nhật giao diện người dùng (xem câu trả lời của Marc Gravell here).

Hy vọng điều này sẽ hữu ích.

+0

Điều này có vẻ giống như một cách tiếp cận hợp lý nếu tôi không thể tìm ra một chờ đợi tin nhắn bơm. Tôi thấy thật khó để tin rằng không có một. Tôi sẽ cập nhật các chủ đề nếu tôi tìm thấy một cái gì đó. –

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