2010-02-21 6 views
10

मेरे पास रिपोर्ट मोड में ListView के साथ एक Windows फ़ॉर्म है। दृश्य में प्रत्येक आइटम के लिए, मुझे एक लंबे समय तक चलने वाले ऑपरेशन करने की आवश्यकता है, जिसके परिणामस्वरूप एक संख्या है।MsgWaitForMultipleObjects के सी # समकक्ष क्या है?

जिस तरह से मैं देशी Win32 में ऐसा करता हूं, वह प्रत्येक आइटम के लिए एक कार्यकर्ता धागा बनाना है (निश्चित रूप से, मैं धागे की असंबद्ध संख्या नहीं बनाऊंगा) और फिर थ्रेड हैंडल की सरणी पर MsgWaitForMultipleObjects()। चूंकि प्रत्येक गणना समाप्त होती है, थ्रेड सिग्नल और मुख्य यूआई थ्रेड उठता है और अपडेट करता है। इस बीच, हम संदेशों को पंप करते हैं ताकि यूआई थ्रेड उत्तरदायी रहे।

कोई भी उदाहरण दे सकता है कि यह सी # में कैसे काम कर सकता है? मैंने मॉनीटर ऑब्जेक्ट को देखा है, और ऐसा लगता है कि मैं क्या चाहता हूं-या अवरुद्ध करते समय संदेश पंप करता है?

धन्यवाद।

संपादित करें: ऐसा लगता है कि WaitHandler.WaitAny() वास्तव में संदेशों को पंप कर सकता है। सीएलआर में संदेश पंपिंग पर cbrumme's treatise देखें।

+0

आप सही हैं, मॉनीटर संदेश पंप नहीं करता है। WaitHandle देखने के लिए एक बेहतर जगह हो सकती है, लेकिन मुझे प्रतीक्षा करेंंडल विधि नहीं मिली जो संदेश को पंप करता था। – itowlson

+0

हाँ, मैंने यह भी देखा। यह एक आवश्यकता नहीं है कि मैं कई वस्तुओं पर इंतजार कर पाऊंगा। मैं एक भी घटना या कुछ के लिए इंतजार करूँगा ... मैं सिर्फ यूआई को अवरुद्ध नहीं करना चाहता हूं। मैंने पाया है कि सभी नमूने 'नींद (100) 'या एक संदर्भ स्विच मजबूर करने के लिए कुछ है, जो बहुत दुखी है। –

+0

मुझे लगता है कि समस्या यह है कि WinForms में संदेश लूप स्पष्ट नहीं है। तो आप सीधे एक MsgWaitX नहीं कर सका, आपको इसके बजाय कुछ ऐसी चीज चाहिए जो एक ईवेंट उठाएगी। उदाहरण के लिए, प्रत्येक उपटस्क को पृष्ठभूमिवर्कर के रूप में चलाएं (और सिंक प्राइमेटिव के बारे में भूल जाएं)। – itowlson

उत्तर

2

लंबे समय से चलने वाली सक्रिय वस्तु, मुझे लगता है, आपके मामले में सबसे अच्छा विकल्प है। मुख्य धागा प्रॉक्सी (सक्रिय वस्तु का) कहते हैं। प्रॉक्सी कॉल विधि को संदेश में परिवर्तित करता है और यह संदेश कतार में जा रहा है। प्रॉक्सी कॉलर को भविष्य की वस्तु पर लौटाता है (यह भविष्य के परिणाम का संदर्भ है)। प्रेषक संदेशों को एक-एक करके हटा देता है और वास्तव में आपके कार्य को अन्य धागे (काम करने वाले धागे) में निष्पादित करता है। जब काम करने वाला धागा कार्य पूरा करता है, तो यह भविष्य की ऑब्जेक्ट के परिणाम को अपडेट करता है या कॉलबैक विधि कॉल करता है (उदाहरण के लिए, अपने यूआई को अपडेट करने के लिए)। डिस्पैडर के पास एक ही समय में एक ही कार्य को निष्पादित करने के लिए कई काम करने वाले धागे हो सकते हैं।

आप यह article (नमूना के साथ) लंबे समय से चल रहे सक्रिय ऑब्जेक्ट पैटर्न के बारे में देख सकते हैं।

+0

कृपया कुछ जानकारी प्रदान करें, न केवल जानकारी के लिंक। –

+0

हम्म, यह वास्तव में ऐसी सरल समस्या को हल करने के लिए बहुत सारे कोड की तरह लगता है। मेरा मतलब है, अगर मैं चाहता था तो मैं हमेशा अपने स्वयं के COM ऑब्जेक्ट को पिनवोक कर सकता हूं। यदि सी # ढांचा पर्याप्त परिपक्व नहीं है, तो मुझे यह आसानी से करने दें, मैं अभी Win32 कोड लिखने के लिए वापस जा सकता हूं। हालांकि मुझे विश्वास करना है कि ऐसा करने का उनका एक आसान तरीका है। –

+0

हां, आप सही हैं। यह एमएसडीएन का एक उदाहरण है: कनेक्शन 1। खोलें(); SqlCommand कमांड 1 = नया SqlCommand (कमांडText1, कनेक्शन 1); IAsyncResult परिणाम 1 = command1.BeginExecuteNonQuery(); WaitHandle waitHandle1 = result1.AsyncWaitHandle; कनेक्शन 2। खोलें(); \t \t ... \t \t WaitHandle [] waitHandles = { waitHandle1, waitHandle2, waitHandle3 }; \t \t बूल परिणाम = WaitHandle.WaitAll (waitHandles, 60000, झूठा); – garik

2

क्या आपका मुख्य धागा प्रबंधक धागा बनाते हैं। इसके लिए आप BackgroundWorker का उपयोग कर सकते हैं। यह प्रबंधक थ्रेड ListView में प्रत्येक आइटम के लिए एक कार्यकर्ता थ्रेड को बंद करता है। यह आपके यूआई को पृष्ठभूमि थ्रेड संसाधित करते समय फांसी के बिना उपयोगकर्ता इनपुट का जवाब देना जारी रखेगा।

अब, समस्या यह है कि प्रत्येक कार्यकर्ता थ्रेड को समाप्त करने के लिए कैसे प्रतीक्षा करें। दुर्भाग्यवश, मैं System.Threading.Thread ऑब्जेक्ट्स के लिए थ्रेड हैंडल प्राप्त करने का कोई तरीका नहीं ढूंढ पाया। मैं यह नहीं कह रहा हूं कि ऐसा करने का कोई तरीका नहीं है; मुझे बस एक नहीं मिला है। इसके लिए एक और जटिल पहलू यह है कि System.Threading.Thread वर्ग को सील कर दिया गया है, इसलिए हम किसी प्रकार का 'हैंडल' प्रदान करने के लिए इसे प्राप्त नहीं कर सकते हैं।

यह वह जगह है जहां मैं ManualResetEvent का उपयोग करता हूं।

मान लें कि प्रत्येक कार्यकर्ता धागा बस ThreadPool धागा है। प्रबंधन BackgroundWorker ListView में प्रत्येक आइटम के लिए ManualResetEvent ऑब्जेक्ट बनाता है। BackgroundWorker प्रत्येक ThreadPool धागा लॉन्च करता है, ManualResetEvent को QueueUserWorkItem function पर तर्क के रूप में पास करें। फिर, प्रत्येक ThreadPool थ्रेड निकास से पहले, ManualResetEvent ऑब्जेक्ट सेट करें।

BackgroundWorker धागा फिर ManualResetEvent ऑब्जेक्ट्स को सरणी में डाल सकता है और WaitHandle.WaitXXX functions का उपयोग करके उस सरणी पर प्रतीक्षा कर सकता है। चूंकि प्रत्येक थ्रेड समाप्त होता है, आप यूआई को अपडेट करने के लिए BackgroundWorker की घटनाओं का उपयोग कर सकते हैं या यूआई को अपडेट करने के लिए Control.Invoke() तकनीक का उपयोग कर सकते हैं (मार्क ग्रेवेल का उत्तर here देखें)।

उम्मीद है कि इससे मदद मिलती है।

+0

यह एक उचित दृष्टिकोण की तरह लगता है अगर मैं एक संदेश पंपिंग प्रतीक्षा नहीं कर सकता। मुझे विश्वास करना मुश्किल लगता है कि कोई नहीं है। अगर मुझे कुछ मिल जाए तो मैं थ्रेड अपडेट करूंगा। –