2012-06-11 14 views
7

मेरे पास एक सी # लाइब्रेरी है जो "मुख्य" ui थ्रेड (यदि कोई मौजूद है) को भेजने/पोस्ट करने की क्षमता रखना चाहती है। इस पुस्तकालय द्वारा इस्तेमाल किया जा सकता है:लाइब्रेरी से मुख्य थ्रेड सिंक्रनाइज़ेशन कॉन्टेक्स्ट या डिस्पैचर को कैप्चर करना

  • एक WinForms आवेदन
  • स्थानीय ऐप्लिकेशन (यूआई) के साथ
  • एक सांत्वना आवेदन (कोई UI के साथ)

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

बातें मैं कोशिश की है:

  1. एक SynchronizationContext:। कैप्चरिंग यह एक Winforms आवेदन (एक WindowsFormsSynchronizationContextCurrent SynchronizationContext के रूप में स्थापित किया जाएगा के लिए ठीक काम करता है यह भी सांत्वना अनुप्रयोग के लिए ठीक काम करता है - के बाद से मैं पता लगा सकता हूं कि वर्तमान सिंक्रनाइज़ेशन कॉन्टेक्स्ट शून्य है (और इस प्रकार, मुझे पता है कि मेरे पास मुख्य थ्रेड पर काम भेजने/पोस्ट करने की क्षमता नहीं है)। यहां समस्या मूल यूआई एप्लीकेशन है: इसमें क्षमता है (यानी यह है एक संदेश पंप), लेकिन वर्तमान सिंक्रनाइज़ेशन संदर्भ शून्य है और इस प्रकार मैं इसे कंसोल ऐप केस से अलग नहीं कर सकता। अगर मैं अंतर कर सकता हूं, तो मैं बस मुख्य थ्रेड पर WindowsFormsSynchronizationContext इंस्टॉल करें, और मुझे जाना अच्छा लगता है।
  2. Dispatcher: Current का उपयोग करके इसे कैप्चर करना एक नया सिंक्रनाइज़ेशन कॉन्टेक्स्ट बनाता है। इस प्रकार, सभी परिस्थितियों में मैं एक डिस्पैचर वापस प्राप्त करूंगा। हालांकि, एक कंसोल ऐप के लिए, पृष्ठभूमि थ्रेड से Dispatcher.Invoke का उपयोग करके (अपेक्षित के रूप में) लटका होगा। मैं Dispatcher.FromThread का उपयोग कर सकता हूं (जो थ्रेड के लिए डिस्पैचर नहीं बनाता है यदि कोई अस्तित्व में नहीं है)। लेकिन मूल यूआई एप्लिकेशन इस विधि का उपयोग कर एक शून्य डिस्पैचर वापस करेगा, और फिर मैं फिर से, यूआई अनुप्रयोग को कंसोल एप्लिकेशन से अलग करने में सक्षम नहीं हूं।
  3. TaskScheduler: मैं FromCurrentSynchronizationContext का उपयोग कर सकता था। सिंक्रनाइज़ेशन कॉन्टेक्स्ट के समान समस्याएं हैं। अर्थात। FromCurrentSyncronizationContext को कॉल करने से पहले, मुझे यह जांचना होगा कि वर्तमान सिंक्रनाइज़ेशन कॉन्टेक्स्ट शून्य है (जो कंसोल ऐप और मूल ui एप्लिकेशन के मामले में होगा)। तो, फिर मैं मूल UI अनुप्रयोग को कंसोल एप्लिकेशन से अलग नहीं कर सकता।

मैं, ज़ाहिर है, मेरी लाइब्रेरी के उपयोगकर्ता निर्दिष्ट किया जाए या नहीं यह एक यूआई आवेदन जब वे मेरी Initialize विधि कॉल है हो सकता था, लेकिन मैं पुस्तकालय यदि संभव हो तो के उपयोगकर्ता के लिए कि जटिलता से बचने के लिए उम्मीद कर रही थी ।

+0

मैं एमएफसी में सी # लाइब्रेरी का उपयोग कर रहा हूं। इस लाइब्रेरी को TaskScheduler.FromCurrentSynchronizationContext() कॉल मिला है। जब मैं एमएफसी एप्लिकेशन चलाता हूं तो यह अपवाद फेंकता है कि 'वर्तमान सिंक्रनाइज़ेशन कॉन्टेक्स्ट को टास्कशेड्यूलर के रूप में उपयोग नहीं किया जा सकता है।' कोई विचार यह कैसे निपटाना है?मैं सीधे एमएफसी में सी # लाइब्रेरी का उपयोग नहीं कर रहा हूं, लेकिन मैंने प्रबंधित सी ++ में एक रैपर बनाया है और मैं इस रैपर का उपयोग एमएफसी एप्लिकेशन में कर रहा हूं। –

उत्तर

5

यह सामान्य रूप से संभव नहीं है, एक लाइब्रेरी जो थ्रेड में उपयोग करने के लिए उपयुक्त है, इस बारे में कोई धारणा नहीं दे सकती कि कौन सा विशेष धागा यूआई थ्रेड है। आप सिंक्रनाइज़ेशन को कैप्चर कर सकते हैं। वर्तमान लेकिन यह केवल यूआई थ्रेड से आपकी प्रारंभिक विधि को बुलाए जाने पर ही सही तरीके से काम करेगा। यह अच्छी तरह से काम करने के लिए बहुत असामान्य नहीं है, जैसे TaskScheduler.FromCurrentSynchronizationContext() दुर्घटना से काम करता है, लेकिन गारंटी नहीं। यदि आप Thread.CurrentThread.GetApartmentState() एसटीए नहीं लौटाते हैं तो आप एक चेक जोड़ सकते हैं, तो यूआई थ्रेड से आपको जो बाधा नहीं कहा जा रहा है, वह बहुत अधिक है। सिंक्रनाइज़ेशन कॉन्टेक्स्ट.क्यूरेंट अक्सर उस मामले में शून्य हो जाएगा, जांचने का एक और तरीका।

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

1

मुझे लगता है कि आप अपने Initialize विधि को यह एक विकल्प बनाने के (या किसी भी तरह अपने कॉलर UI इंटरैक्शन अनुरोध करने के लिए अनुमति देते हैं), मुझे लगता है कि बस अधिक समझ में आता है चाहिए। मुझे विनिर्देशों को नहीं पता लेकिन ये मुझे "विनम्र" काम करने के लिए प्रतीत होता है, अपने कॉलर को यह तय करने दें कि वे चाहते हैं कि आप चाहते हैं या आप अपने यूआई का समर्थन करना चाहते हैं। मैं इसे एक कदम आगे ले जाऊंगा और यहां तक ​​कि कॉलर सिंक्रनाइज़ेशन संदर्भ की आपूर्ति करने के लिए भी। लेकिन यह मेरी राय है।

अपने प्रश्न का उत्तर देने के लिए, कुछ "हैक" हैं जिनका उपयोग आप यह निर्धारित करने के लिए कर सकते हैं कि आप कंसोल आवेदक में चल रहे हैं या नहीं।इस SO प्रश्न पर कुछ जानकारी है: C#/.NET: Detect whether program is being run as a service or a console application

+0

धन्यवाद। मूल एमएफसी एप्लिकेशन के लिए सिंक्रनाइज़ेशन कॉन्टेक्स्ट को क्या प्रदान करना चाहिए? एक WindowsFormsSynchronizationContext बस ठीक काम करेगा, लेकिन यह उनके लिए कुछ अजीब लगता है। –

+1

मुझे थोड़ा सा शोध करना होगा या किसी ऐसे व्यक्ति से परामर्श करना होगा जो एमएफसी से अधिक परिचित है, यह एक बहुत ही लंबा समय रहा है क्योंकि मैंने एमएफसी के साथ काम किया है, इसलिए मुझे यकीन भी नहीं है। मेरा मुद्दा यह था कि मैं उन प्रकार के विकल्पों में "बेकिंग" का बड़ा प्रशंसक नहीं हूं, खुलेपन और लचीलापन आमतौर पर बेहतर विकल्प बन जाता है। – CodingGorilla

0

सिंक्रनाइज़ेशन कॉन्टेक्स्ट पैरामीटर रखने के लिए लाइब्रेरी प्रारंभिक बदलें। यदि पैरामीटर शून्य है तो लाइब्रेरी को कुछ विशेष करने की आवश्यकता नहीं है, अगर शून्य नहीं है तो वहां पोस्ट करें/जीयूआई अपडेट भेजें।

-1

मुझे लगता है कि यह वास्तव में AsyncOperationManager.CreateOperation() है। “Implementing the Event-based Asynchronous Pattern” राज्य:

इवेंट-आधारित असिंक्रोनस पैटर्न एक वर्ग को पैकेज करने के लिए एक मानक तरीका प्रदान करता है जिसमें असीमित विशेषताएं हैं। यदि AsyncOperationManager जैसे सहायक वर्गों के साथ कार्यान्वित किया गया है, तो आपकी कक्षा किसी भी एप्लिकेशन मॉडल के तहत सही ढंग से काम करेगी, जिसमें एएसपी.नेट, कंसोल एप्लिकेशन और विंडोज फॉर्म एप्लिकेशन शामिल हैं।

यह कॉलर पर निर्भर करता है कि वे यूआई थ्रेड पर अपना एपीआई कॉल करना चाहते हैं या नहीं। यदि वे करते हैं, तो यह संदर्भ को कैप्चर करेगा और ईवेंट संदेश पंप के माध्यम से क्रमबद्ध होंगे। कंसोल एप्लिकेशन में आप एक ही व्यवहार प्राप्त कर सकते हैं यदि आप एक सिंक्रनाइज़ेशन कॉन्टेक्स्ट स्थापित करते हैं जैसे कि Nito.AsyncEx nuget पैकेज से आप मुफ्त में प्राप्त करते हैं। अतिरिक्त संपत्ति की आवश्यकता नहीं है या सशर्त कोड स्वयं लिखना है। यदि कोई धारावाहिक सिंक्रनाइज़ेशन संदर्भ उपलब्ध नहीं है, तो AsyncOperation.Post() कंसोल ऐप्स पर उपलब्ध नकली सिंक्रनाइज़ेशन संदर्भ का उपयोग करेगा जो केवल ईवेंट को थ्रेडपूल पर कतारबद्ध करता है (जिसका अर्थ है कि पद क्रम में निष्पादित नहीं हो सकते हैं)। पूरा होने पर AsyncOperation.OperationCompleted() या AsyncOperation.PostOperationCompleted() पर कॉल करना याद रखें।

पुस्तकालय में मैं कुछ पर कब्जा करना चाहते हैं (ए SynchronizationContext, एक डिस्पैचर, एक कार्य शेड्यूलर, या कुछ और) प्रारंभ दौरान

यह वास्तव में क्या AsyncOperationManager.CreateOperation() करता है, और एक वातावरण में नैदानिक ​​तरीका। लेकिन आपको इसे OperationCompleted() पर कॉल के साथ युग्मित करने का प्रयास करना चाहिए, जो कि आप जिस एपीआई को बेनकाब करना चाहते हैं उसे शायद अधिक कठिन होगा। AsyncOperation का उपयोग करने का सबसे आसान तरीका एक ऑपरेशन शुरू करना होगा जब आपकी लाइब्रेरी वास्तव में प्रारंभिकरण के दौरान ऑपरेशन शुरू करती है। या प्रारंभिक दिनचर्या को IDisposable संदर्भ ऑब्जेक्ट हैंडल लौटने से उपभोक्ता को संकेत मिलेगा कि उन्हें अपने जीवनकाल को प्रबंधित करने की आवश्यकता है।

संबंधित मुद्दे

 संबंधित मुद्दे