2010-01-18 13 views
5

क्या पृष्ठभूमि वर्कर सी # थ्रेड सुरक्षित है?कैसे सुनिश्चित करें यूआई उत्तरदायी है पृष्ठभूमिवर्कर

कारण मैं इस पूछना क्योंकि मैं इसके साथ एक अलग धागे पर एक नियंत्रण करने के लिए parented नहीं जा सकती है

अपवाद एक धागे पर बनाया गया एक

नियंत्रण हो जाता है। यह मेरा DoWork घटना कोड है:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) 
{ 



    var openFile = document.Open(MyFileName); 
    e.Result = openFile; 
} 

जहां document एक UI नियंत्रण है कि जब माता पिता प्रपत्र बनाई गई है आरंभ नहीं हो जाता है। Open विधि के दौरान document में विभिन्न गुणों को भर दिया जाएगा।

मैंने कोड को बदलने के लिए कोड बदलने की कोशिश की, फिर भी वही समस्या बनी रहती है। i.e,

document.GetType().GetMethod("Open)".Invoke(document, new object[]{MyFileName}) 

उपरोक्त के समान त्रुटि उत्पन्न करेगा।

कोई विचार कैसे document नियंत्रण में हेरफेर करना है? दूसरे शब्दों में, उपर्युक्त कोड कैसे काम करें?

संपादित करें: यह सुझाव दिया गया था कि मैं Control.Invoke का उपयोग करता हूं, लेकिन यह अभी भी काम नहीं करता है (दोनों थ्रेड फांसी)। इस कोड को मैंने कोशिश की है:

private delegate bool OpenFile(string filePath); 
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) 
{ 



    OpenFile oF = new OpenFile(document.Open); 
    var openFile = Invoke(oF, MyFileName); // it doesn't really matter whether I use BeginInvoke or Invoke, or other Control.Invoke, the end result is the same. Both the main thread hosting the document and the thread that launches the UI hanged. 

    e.Result = openFile; 
} 

उत्तर

1

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

Invoke(new Action(MethodToRunInUIThread)); 

void MethodToRunInUIThread() { 
    // do stuff here. 
} 

वैसे, ऐसा नहीं यदि आप जो कुछ भी कर रहे हैं वह पृष्ठभूमि कार्यकर्ता का उपयोग करने के लिए समझ में नहीं आता है, तो यूआई ऑब्जेक्ट्स में हेरफेर करना है।

+0

@ मेहद्राड, मुझे UI उत्तरदायी रखने के लिए पृष्ठभूमि कार्यकर्ता की आवश्यकता है, जो * है * यह समझ में क्यों आता है। – Graviton

+0

@Ngu जल्द ही: निश्चित रूप से, यदि आपके पास लंबे समय तक चलने वाला कार्य है जो केवल यूआई ऑपरेशंस नहीं है, तो आप इसका उपयोग करेंगे। यदि * डूवर्क 'विधि में आप * ऑल ऑब्जेक्ट्स में हेरफेर करना चाहते हैं, तो आपको' BackgroundWorker' का उपयोग नहीं करना चाहिए और कारण यह है कि आपको अंततः यूआई थ्रेड पर उन सभी यूआई ऑपरेशंस करना होगा। –

+0

यह समझ में आता है और यह अधिक सूक्ष्म हो सकता है। धागा सिर्फ "यूआई थ्रेड" को सूचित कर सकता है कि "कुछ नया हुआ", और उसके बाद यूआई को जो भी अधिसूचना हैंडलर पर यूआई को अपडेट करने के लिए यूआई को अपडेट करना है। –

0

पृष्ठभूमिवर्कर एक धागा आधारित संरचना है। थ्रेड-सुरक्षा मामले एक साथ काम करते समय कार्यों के बारे में है। हो सकता है कि आप जो मांगते हैं वह Winforms नियंत्रणों के बारे में है जो उपयोगकर्ता इंटरफ़ेस थ्रेड के अद्वितीय थ्रेड के माध्यम से उपयोग किए जाते हैं।

2

या तो आप मेहरद अफशारी के रूप में आवेदक के रूप में आवेदक कर सकते हैं, या आप बीजीडब्ल्यू की प्रगति घटना का उपयोग कर सकते हैं जो यूआई थ्रेड पर वापस आती है। या काम पूरा हुआ जो यूआई थ्रेड पर वापस आता है। दोनों के बीच का अंतर वर्ककंपलेट को अंत में केवल एक बार निकाल दिया जाता है। DoWork से प्रगति आपके द्वारा निकाल दी गई है।

+0

"यूजी थ्रेड पर वापस आने वाले बीजीडब्ल्यू की प्रगति घटना का उपयोग कैसे करें" मेरी समस्या हल करें, अर्थात्, एक उत्तरदायी यूआई प्राप्त करने में सक्षम होना? – Graviton

+2

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

5

यह थ्रेड नहीं है कि समस्या यह है कि यह यूआई नियंत्रण पर एक विधि को कॉल करने का प्रयास कर रहा है। दोनों डब्ल्यूपीएफ और विनफॉर्म नियंत्रणों में केवल यूआई थ्रेड पर कॉल किया जा सकता है (जिसमें से आमतौर पर एक होता है)। आप यह नहीं कहते कि आप किसका उपयोग कर रहे हैं लेकिन आपको WinForms के लिए Control.Invoke विधि या WPF के लिए Dispatcher.Invoke पर कॉल करने की आवश्यकता है।

Invoke() आपके द्वारा दिखाए गए प्रतिबिंब विधि वास्तव में वर्तमान धागे पर विधि का आह्वान करेंगे।

+0

मैंने अपने DoWork ईवेंट में कोड के इस टुकड़े को आजमाया, और यह अभी भी काम नहीं करता है: 'this.Invoke (document.Open)' – Graviton

+0

आप अभी भी गलत विधि को कॉल कर रहे हैं। यदि 'दस्तावेज़' एक विंडोज़ फॉर्म नियंत्रण है तो आप 'document.Invoke (MyMethod) 'कहेंगे, जहां' MyMethod' एक प्रतिनिधि है जो 'दस्तावेज़' खोलता है। ओपन'। हस्ताक्षर के आधार पर आप 'document.Invoke (document.Open) 'को सीधे कॉल करने में सक्षम हो सकते हैं। – GraemeF

+0

@GraemeF, अगर 'document.Invoke' उपलब्ध नहीं है तो क्या होगा? – Graviton

1

यदि यूआई नियंत्रण की उस कार्यक्षमता को निष्पादित करने में लंबा समय लगता है, तो आप ऐसा नहीं कर सकते हैं। "फ्रीजिंग" तब होता है जब यूआई थ्रेड पर एक लंबे समय से चलने वाला ऑपरेशन होता है, और यदि नियंत्रण का वह फ़ंक्शन विशेष रूप से थ्रेड-सुरक्षित नहीं बनाया गया था, तो इसे मुख्य थ्रेड पर चलाना चाहिए।

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

चूंकि आपने यह निर्दिष्ट किया है कि यह आपकी टिप्पणियों में एक तृतीय पक्ष नियंत्रण है, तो आप यहां भाग्य से बाहर हो सकते हैं।

0

@ ग्रेविटन, उत्तर के साथ एक संबंधित कार्य here पाया गया है। वह व्यक्ति टेक्स्टबॉक्स अपडेट करने के लिए पृष्ठभूमिवर्कर का उपयोग कर रहा था, वही अवधारणा लागू होती है (आपका केवल एक कार्यकर्ता धागा है)।

+0

हाँ यकीन है कि यह करता है, मेरा अद्यतन प्रश्न देखें। मैंने पाया कि आपके लिंक में निर्दिष्ट तकनीक को लागू करने के बाद दोनों थ्रेड फांसी दी गईं। – Graviton

+0

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

0

आपको DoWork में Control.BeginInvoke() का उपयोग करने की आवश्यकता है। यह प्रतिनिधि को असीमित रूप से निष्पादित करता है और इसलिए यह सुनिश्चित करेगा कि कॉलिंग थ्रेड "लटका" नहीं होगा।

Control.Invoke() अन्य धागे पर प्रतिनिधि को निष्पादित करेगा, लेकिन कॉलिंग थ्रेड को पूरा होने के लिए इंतजार कर देगा।

आम तौर पर विंडोज फॉर्म में आप कंट्रोल.बिनिन इनवोक() का उपयोग करके बेहतर हो जाते हैं, जहां भी थ्रेड के बीच डेडलॉकिंग से बचने में मदद मिलती है, जब एक धागा दूसरे के लिए इंतजार कर रहा है, जैसे Control.Invoke()।

यदि "दस्तावेज़" ऑब्जेक्ट System.Windows.Forms.Control से प्राप्त होता है, तो आप बस दस्तावेज़ को कॉल कर सकते हैं। BginginInvoke (myDelegate)।

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

ऐसा लगता है कि आप विभिन्न Invoke/BeginInvoke प्रकारों (समझने योग्य) के बारे में उलझन में हैं। यह पहले सवाल: What is the difference between Invoke and BeginInvoke? और जॉन स्कीट्स उत्तर को चीजों को स्पष्ट करने में मदद करनी चाहिए।

+0

मैं समझता हूं, लेकिन जब मैंने 'BeginInvoke'' कहा था, तो 'दस्तावेज़' को होस्ट करने वाला थ्रेड और एक अन्य थ्रेड जो एक चलती संवाद बॉक्स को लॉन्च करता है। – Graviton

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