2010-02-21 29 views
10

Rapor Modunda Liste Görünümü olan bir Windows Formum var. Görünümdeki her öğe için, uzun süreli bir işlem yapmam gerekiyor, bunun sonucu bir sayı.MsgWaitForMultipleObjects C# eşdeğeri nedir?

Yerel win32'de yapmamın yolu, her öğe için bir işçi iş parçacığı oluşturmaktır (naif; tabii ki, sınırlı sayıda iş parçacığı oluşturmayacağım) ve daha sonra iş parçacığı iş parçacığı dizisinde MsgWaitForMultipleObjects(). Her hesaplama bittiğinde, iş parçacığı sinyali ve ana UI iş parçacığı uyanır ve güncelleştirilir. Bu arada, UI iş parçacığı yanıt vermeye devam etmek için iletileri pompalarız.

Bu, C# 'da nasıl çalışabileceğine dair bir örnek verebilir mi? Monitor nesnesine baktım ve istediğim gibi görünmüyor - ya da engelleme sırasında iletileri pompalıyor mu?

Teşekkürler.

Düzenleme: Görünüşe göre WaitHandler.WaitAny() aslında iletileri pompalayabilir. CLR'deki mesaj pompalamada bkz. cbrumme's treatise.

+0

Haklısınız, Monitör mesajları pompalamıyor. WaitHandle, bakmak için daha iyi bir yer olabilir, ancak iletileri de pompalayan bir WaitHandle yöntemi bulamadım. – itowlson

+0

Evet, onu da gördüm. Birden fazla nesneyi bekleyebilmem şart değil. Tek bir olay ya da bir şey için bekleyeceğim ... UI'yi engellemek istemiyorum. Bulduğum tüm örnekler uykuyu (100) veya bağlam anahtarını zorlamak için bir şey yapıyor, bu çok üzücü. –

+0

Sorun şu ki, WinForms'ta mesaj döngüsü açık değil. Yani doğrudan bir MsgWaitX yapamazsınız, bunun yerine bir etkinliği başlatacak bir şeye ihtiyacınız var. Örneğin, her alt görevi bir BackgroundWorker olarak çalıştırın (ve eşitleme ilkellerini unutun). – itowlson

cevap

2

Uzun süredir çalışan aktif nesne sanırım sizin durumunuzda en iyi seçimdir. Ana iş parçacığı proxy'yi (etkin nesnenin) çağırır. Proxy, çağrı yöntemini iletiye dönüştürür ve bu ileti bir sıraya gider. Proxy, arayan kişiye gelecekteki nesneyi döndürür (bu, gelecekteki sonuca referanstır). Dağıtım memuru mesajları tek tek sıfıra indirir ve görevinizi diğer iş parçacığında (çalışan iş parçacığı) yürütür. Çalışan iş parçacığı bir görevi tamamladığında, gelecekteki nesnenin sonucunu güncelleştirir veya geri çağrı yöntemini çağırır (örneğin, UI'nizi güncellemek için) .Dispather, aynı anda birden fazla görevi yürütmek için çok sayıda iş parçacığına sahip olabilir.

Uzun süreli etkin nesne kalıbı hakkında bu örnekte bu article (örnekle birlikte) görebilirsiniz.

+0

Lütfen sadece bilgi bağlantılarını değil, bazı bilgileri sağlayın. –

+0

Hmm, gerçekten böyle basit bir sorunu çözmek için çok fazla kod gibi görünüyor. İstediğim zaman kendi COM nesnesini her zaman tutabilirdim. C# framework, bunu kolayca yapmama izin verecek kadar olgun değilse, win32 kodu yazmaya geri dönebilirim. Her ne kadar onların bunun için kolay bir yol olduğuna inanmak zorundayım. –

+0

Evet, haklısınız. Bu MSDN'den bir örnektir: connection1.Open(); SqlCommand command1 = yeni SqlCommand (commandText1, connection1); IAsync Sonuç sonucu1 = komut1.BeginExecuteNonQuery(); WaitHandle waitHandle1 = sonuç1.AsyncWaitHandle; bağlantı2.Open(); \t \t ... \t \t WaitHandle [] waitHandles = { waitHandle1, waitHandle2, waitHandle3 }; \t bool result = WaitHandle.WaitAll (waitHandles, 60000, false); – garik

2

Ana iş parçacığınızın bir yönetici iş parçacığı oluşturmasını sağlayın. Bunun için BackgroundWorker kullanabilirsiniz. Bu yönetici iş parçacığı, ListView'deki her öğe için bir çalışan iş parçacığı başlatır. Bu, kullanıcı arayüzünüzün arka plan iş parçacıkları işlenirken askıda kalmadan kullanıcı girişine yanıt vermesine olanak tanır.

Şimdi, sorun, her bir iş parçacığının bitmesini beklemek. Ne yazık ki, System.Threading.Thread nesneleri için bir iş parçacığı tanıtımı almak için bir yol bulamadık. Bunu yapmanın bir yolu olmadığını söylemiyorum; Ben sadece bir tane bulamadım. Bunun bir başka karmaşık yönü de System.Threading.Thread sınıfının mühürlenmiş olmasıdır, bu yüzden bir çeşit 'tutamaç' sağlamak için ondan türememiz mümkün değildir.

ManualResetEvent'u kullandığım yer burası.

Her çalışan iş parçacığının yalnızca bir ThreadPool iş parçacığı olduğunu varsayalım. BackgroundWorker'u yönetme, ListView'deki her öğe için bir ManualResetEvent nesnesi oluşturur. BackgroundWorker her ThreadPool iş parçacığı başlatırken, ManualResetEvent öğeyi QueueUserWorkItem function'a bir argüman olarak iletin. Ardından, her ThreadPool iş parçacığı çıkmadan hemen önce ManualResetEvent nesnesini ayarlayın.

BackgroundWorker iş parçacığı, ManualResetEvent nesnesinin tümünü bir diziye ekleyebilir ve WaitHandle.WaitXXX functions kullanarak bu dizide bekleyebilir. Her iş parçacığı bittiğinde, UI'yi güncellemek için BackgroundWorker'un etkinliklerini kullanabilir veya UI'yi güncellemek için Control.Invoke() tekniğini kullanabilirsiniz (bkz. Marc Gravell'in yanıtı here).

Bu yardımcı olur umarım.

+0

Bu, mesaj pompalama beklemesini anlayamazsam mantıklı bir yaklaşım gibi görünüyor. Orada olmadığını düşünmek çok zor. Bir şey bulursam iş parçacığı günceller. –