2009-12-05 16 views
20

मैं this SO question से गुजर चुका हूं लेकिन इससे मदद नहीं मिली है।अमान्यऑपरेशन अपवाद - ऑब्जेक्ट वर्तमान में अन्यत्र उपयोग में है

यहां मामला अलग है। मैं पृष्ठभूमि कार्यकर्ताओं का उपयोग कर रहा हूँ। 1 BackgroundWorker उपयोगकर्ता की छवि इनपुट पर और अंदर firstbackgroundworker_runworkercompleted() मैं 3 अन्य backgroundworkers

algo1backgroundworker.RunWorkerAsync(); 
algo2backgroundworker.RunWorkerAsync(); 
algo3backgroundworker.RunWorkerAsync(); 

बुला उपयोग कर रहा हूँ काम कर शुरू होता है इस से प्रत्येक के लिए कोड है:

algo1backgroundworker_DoWork() 
{ 
Image img = this.picturebox.Image; 
imgclone = img.clone(); 
//operate on imgclone and output it 
} 

algo2backgroundworker_DoWork() 
{ 
Image img = this.picturebox.Image; 
imgclone = img.clone(); 
//operate on imgclone and output it 
} 

समान संचालन अन्य में किया जाता algo * backgrougrondworker_doWork()।

अब कुछ समय मुझे मिल रहा है "अवैधऑपरेशन अपवाद - ऑब्जेक्ट वर्तमान में कहीं और उपयोग में है"। यह बहुत मनमाना है। मुझे कभी-कभी यह algo1backgroundworker_DoWork में मिलता है और कभी-कभी algo2backgroundworker_DoWork में और कभी-कभी एप्लिकेशन में। Run (नया myWindowsForm());

मुझे क्या हो रहा है इसके बारे में कोई जानकारी नहीं है।

उत्तर

39

जीडीआई + के अंदर एक ताला है जो दो धागे को एक ही समय में बिटमैप तक पहुंचने से रोकता है। यह एक अवरुद्ध प्रकार का ताला नहीं है, यह एक "प्रोग्रामर ने कुछ गलत किया है, मैं एक अपवाद फेंक दूंगा" लॉक की तरह। आपके धागे बमबारी कर रहे हैं क्योंकि आप सभी धागे में छवि (== बिटमैप तक पहुंचने) को क्लोन कर रहे हैं। आपका यूआई थ्रेड बमबारी कर रहा है क्योंकि यह बिटमैप को खींचने की कोशिश कर रहा है (== बिटमैप तक पहुंच रहा है) उसी समय एक धागा इसे क्लोन कर रहा है।

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

19

तो ऐसा लगता है कि आपके BackgroundWorkers एक ही समय में एक ही विंडोज़ फॉर्म घटकों तक पहुंचने का प्रयास कर रहे हैं। यह समझाएगा कि विफलता यादृच्छिक क्यों है।

आप यकीन है कि यह शायद इसलिए की तरह, एक lock का उपयोग करके ऐसा नहीं होता है बनाने के लिए की आवश्यकता होगी:

 private object lockObject = new object(); 

    algo1backgroundworker_DoWork() 
    { 
     Image imgclone; 
     lock (lockObject) 
     { 
     Image img = this.picturebox.Image; 
     imgclone = img.clone(); 
     } 
     //operate on imgclone and output it 
    } 

नोट मुझे यकीन है कि imgclone इस विधि के लिए स्थानीय है कि - आप निश्चित रूप से नहीं इसे सभी तरीकों से साझा करना चाहते हैं!

दूसरी ओर एक ही लॉक ऑब्जेक्ट उदाहरण सभी विधियों द्वारा उपयोग किया जाता है। जब एक पृष्ठभूमिवर्कर विधि lock{} अनुभाग में प्रवेश करती है, तो उस बिंदु पर आने वाले अन्य लोग अवरुद्ध हो जाएंगे। इसलिए यह सुनिश्चित करना महत्वपूर्ण है कि लॉक किए गए अनुभाग में कोड तेज़ है।

जब आप अपनी संसाधित छवि "आउटपुट" पर आते हैं, तो यह सुनिश्चित करने के लिए भी सावधान रहें कि आप यूआई में क्रॉस-थ्रेड अपडेट नहीं करते हैं। इससे बचने के लिए एक साफ तरीके से this post देखें।

1

विंडोज़ फॉर्म में न केवल आपको केवल एक थ्रेड से नियंत्रणों तक पहुंचना चाहिए, लेकिन वह धागा मुख्य अनुप्रयोग थ्रेड होना चाहिए, थ्रेड जिसने नियंत्रण बनाया है।

इसका मतलब है कि DoWork में आपको किसी भी नियंत्रण तक नहीं पहुंचना चाहिए (Control.Invoke का उपयोग किए बिना)। तो यहां आप RunWorkerAsync को अपने छवि क्लोन में गुजरने के लिए कॉल करेंगे। DoWork इवेंट हैंडलर के अंदर, आप DoWorkEventArgs.Argument से पैरामीटर निकाल सकते हैं।

केवल प्रगतिChanged और RunWorker पूर्ण ईवेंट हैंडलर जीयूआई के साथ बातचीत करनी चाहिए।