2009-06-29 9 views
30

मेरे पास एक सी # डेस्कटॉप एप्लिकेशन है जिसमें एक थ्रेड जो मैं लगातार बनाता हूं, एक स्रोत से एक छवि प्राप्त करता है (यह वास्तव में एक डिजिटल कैमरा है) और इसे पैनल (पैनल। छवि = img) जीयूआई मेंअमान्यऑपरेशन अपवाद - ऑब्जेक्ट वर्तमान में कहीं और उपयोग में है - लाल क्रॉस

(के रूप में यह एक नियंत्रण के कोड-पीछे है जो एक और धागा होना चाहिए।

आवेदन काम करता है लेकिन कुछ मशीनों मैं यादृच्छिक समय अंतराल पर निम्न त्रुटि (अप्रत्याशित पाने पर)

************** Exception Text ************** 
System.InvalidOperationException: The object is currently in use elsewhere. 

फिर पैनल लाल रेड, लाल एक्स में बदल जाता है - मुझे लगता है कि यह अमान्य चित्र आइकन है जो गुणों से संपादन योग्य है। आवेदक आयन काम करता रहता है लेकिन पैनल कभी अपडेट नहीं होता है।

जो मैं यह कह सकता हूं कि यह त्रुटि नियंत्रण की घटना से आता है जहां मैं तस्वीर पर कुछ और खींचता हूं।

if (this.ReceivedFrame != null) 
{ 
    Delegate[] clients = this.ReceivedFrame.GetInvocationList(); 
    foreach (Delegate del in clients) 
    { 
     try 
     { 
      del.DynamicInvoke(new object[] { this, 
       new StreamEventArgs(frame)}); 
     } 
     catch { } 
    } 
} 

इस प्रतिनिधि है:

मैं वहाँ एक ताला लेकिन कोई किस्मत :(

इस प्रकार

तरह से मैं समारोह है कि पैनल पर छवि डालता फोन है उपयोग करने की कोशिश

public delegate void ReceivedFrameEventHandler(object sender, StreamEventArgs e); 
    public event ReceivedFrameEventHandler ReceivedFrame; 

और यह कैसे नियंत्रण कोड-पीछे अंदर समारोह इसे करने के लिए पंजीकृत करता है:

Camera.ReceivedFrame += 
    new Camera.ReceivedFrameEventHandler(camera_ReceivedFrame); 

मैं भी कोशिश की

del.Method.Invoke(del.Target, new object[] { this, new StreamEventArgs(b) }); 
बजाय

del.DynamicInvoke(new object[] { this, new StreamEventArgs(frame) }); 

लेकिन कोई किस्मत

किसी को भी पता है कि कैसे मैं कम से कम इस त्रुटि को ठीक या त्रुटि किसी भी तरह पकड़ने और धागा बना सकता है एक बार फिर पैनल पर छवियों को डाल दिया?

उत्तर

0

मुझे लगता है कि इस multithreading है समस्या उपयोग खिड़कियों सुनहरा नियम और मुख्य थ्रेड उपयोग में पैनल को अद्यतन panel.Invoke इस पार सूत्रण अपवाद

+0

मैं मुख्य थ्रेड में पैनल अपडेट कर रहा हूं लेकिन मैं उस फ़ंक्शन को कॉल कर रहा हूं जो इसे अन्य थ्रेड से अपडेट करता है और छवि को पैरामीटर के रूप में पास करता है। –

+0

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

18

इसका कारण यह है GDI + छवि वर्ग सुरक्षित थ्रेड नहीं है पर काबू पाने चाहिए।

Image DummyImage; 

// Paint 
lock (DummyImage) 
    e.Graphics.DrawImage(DummyImage, 10, 10); 

// Access Image properties 
Size ImageSize; 
lock (DummyImage) 
    ImageSize = DummyImage.Size; 

Btw, मंगलाचरण की जरूरत नहीं है, यदि आप ऊपर पैटर्न का उपयोग करेगा: आप जब आप चित्र या हो रही छवि का आकार के लिए उदाहरण के लिए, छवि का उपयोग करने की जरूरत है हर बार ताला का उपयोग करके InvalidOperationException से बच सकते हैं Hovewer।

+0

अच्छी तरह से नहीं फ़ंक्शन जो ऑनपेंट इवेंट के अंदर चलता है, उस छवि के ऊपर पैनल पर बहुत सारी चीजें खींचता है जो पैनल पर अन्य थ्रेड सेट करता है, इसलिए मैं खींचा जाने वाला सदाबहार कैसे लॉक कर सकता हूं? इसमें आयताकार, रेखाएं और छवियां शामिल हैं –

+0

मैंने पैनल को लॉक किया है लेकिन यह काम नहीं किया है मुझे अभी भी त्रुटि मिली है –

+0

आपको पैनल लॉक करने की आवश्यकता नहीं है, आपको उस विशेष छवि को लॉक करने की आवश्यकता है जिसके साथ आप काम करते हैं। – arbiter

2

मुझे लगता है कि एक ही कैमरा ऑब्जेक्ट कई बार उपयोग किया जाता है।

उदा। प्रत्येक प्राप्त फ्रेम के लिए एक नया बफर का उपयोग करने का प्रयास करें। ऐसा लगता है कि, जब चित्र बॉक्स नया फ्रेम खींच रहा है, तो आपकी कैप्चर लाइब्रेरी उस बफर को फिर से भरती है। इसलिए तेज मशीनों पर यह एक मुद्दा नहीं हो सकता है, धीमी मशीनों के साथ यह एक मुद्दा हो सकता है।

प्रत्येक प्राप्त फ्रेम के बाद, मैंने एक बार कुछ समान प्रोग्राम किया है, हमें अगले फ्रेम प्राप्त करने का अनुरोध करना था और उस अनुरोध में नया फ्रेम प्राप्त बफर सेट करना था।

आप ऐसा नहीं कर सकते हैं, तो प्राप्त फ्रेम कैमरे से पहले एक नया बफर करने के लिए कॉपी और एक कतार में है कि बफर जोड़ सकते हैं या सिर्फ 2 बारी बफ़र्स का उपयोग करें और लगने लिए जाँच करें। या तो myOutPutPanel.BeginInvoke का उपयोग करें कैमरा_ReceivedFrame विधि को कॉल करने के लिए, या बेहतर एक धागा चल रहा है, जो कतार की जांच करता है, जब इसकी एक नई प्रविष्टि होती है तो यह mnyOutPutPanel.BeginInvoke को कॉल पर छवि के रूप में नया बफर सेट करने के लिए अपनी विधि का आह्वान करने के लिए कॉल करता है।

इसके अलावा, एक बार जब आप बफर प्राप्त कर लेते हैं, तो छवि की सेटिंग का आह्वान करने के लिए पैनल आमंत्रण विधि का उपयोग करें (गारंटी है कि यह विंडो थ्रेड में चलता है और आपकी कैप्चर लाइब्रेरी से धागा नहीं)।

उदाहरण नीचे किसी भी धागा (कब्जा पुस्तकालय या अन्य अलग थ्रेड) से कहा जा सकता है:

void camera_ReceivedFrame(object sender, StreamEventArgs e) 
{ 
    if(myOutputPanel.InvokeRequired) 
    { 
     myOutPutPanel.BeginInvoke( 
      new Camera.ReceivedFrameEventHandler(camera_ReceivedFrame), 
      sender, 
      e); 
    } 
    else 
    { 
     myOutPutPanel.Image = e.Image; 
    } 
} 
4

मैं एक ही त्रुटि संदेश के साथ एक समान समस्या थी लेकिन जैसा कि मैंने शायद कोशिश, लॉकिंग बिटमैप नहीं था ' मेरे लिए कुछ भी ठीक नहीं है। तब मुझे एहसास हुआ कि मैं एक स्थिर ब्रश का उपयोग कर एक आकृति खींच रहा था। निश्चित रूप से, यह ब्रश था जो थ्रेड विवाद पैदा कर रहा था।

var location = new Rectangle(100, 100, 500, 500); 
var brush = MyClass.RED_BRUSH; 
lock(brush) 
    e.Graphics.FillRectangle(brush, location); 

यह मेरे मामले और सबक के लिए काम किया है सीखा: सभी संदर्भ प्रकार बिंदु है जहां धागा विवाद उत्पन्न हो रही है पर इस्तेमाल किया जा रहा की जाँच करें।

+1

मेरे मामले में यह ब्रश भी था। बस मस्ती के लिए मैंने इसे फ़ॉन्ट के साथ करने की कोशिश की लेकिन ऐसा लगता है कि यह कई धागे से काम करता है। –