2010-12-06 24 views
5

मैं सी # में एक ऐप लिख रहा हूं जो कुछ उपकरणों के साथ संवाद करने के लिए SerialPort कक्षा का उपयोग करता है। अब बड़ी समस्या यह है कि मैं हर समय सामना कर रहा हूं कि वहां संसाधनों को सही तरीके से कैसे मुक्त किया जाए, क्योंकि पहले से ही इस्तेमाल होने वाले सीरियल पोर्ट का उपयोग करने का प्रयास करते समय आपको तुरंत अपवाद मिलता है।सीरियल पोर्ट को ठीक से

के बाद से सामान्य रूप से जीसी काम मैं थोड़े विचारों और क्या प्रयास करने के लिए से बाहर कर रहा हूँ के सबसे का ध्यान रखना चाहिए ...

मुख्य रूप से मैं 2 बातें जो (मेरे तर्क में) काम करना चाहिए की कोशिश की। मैं सत्र आधारित संचार का उपयोग करता हूं, इसलिए मैं प्रत्येक संचार से पहले और बाद में OpenPort और ClosePort विधि को कॉल करता हूं - इसलिए बंदरगाह बंद होना चाहिए। इसके अलावा मैंने बंदरगाह को बाद में बंद करने के लिए अपनी ऑब्जेक्ट को सेट करने का प्रयास किया है - लेकिन फिर भी मुझे UnauthorizedAccessExceptions हर समय मिलता है - हालांकि मुझे 100 प्रतिशत यकीन है कि SerialPort.Close() विधि को कॉल किया गया है।

क्या आप बंदरगाहों को मुक्त करने के किसी भी बेहतर तरीके से जानते हैं, इसलिए मैं उस अपवाद को रोकना बंद कर देता हूं?

संपादित करें: जवाब लेकिन निपटान() सामान काम नहीं कर रहा के लिए धन्यवाद - मैं कोशिश की थी कि इससे पहले कि - शायद मैं कुछ हालांकि इसलिए यहाँ गलत कर रहा हूँ एक उदाहरण है कि मेरे कोड लगता है:

class clsRS232 : IDisposable 
{ 
    public void clsRS232() 
    { 
    Serialport port = new Serialport("COM1",9600,Parity.none,8,Stopbits.one); 
    } 
    public void openPort() 
    { 
    port.Open(); 
    } 
    public void sendfunc(string str) 
    { 
    port.Write(str); 
    } 
    public string readfunc() 
    { 
    port.ReadTo("\n"); 
    } 

    public void Dispose() 
    { 
    port.Dispose(); 
    } 

} 

अब जब भी मैं RS232 संचार मैं कैलोरी की जरूरत है:

तो यह मेरी आवरण वर्ग होगा: लेकिन काम नहीं करता है या तो - यह वास्तव में काफी की तरह Øyvind सुझाव दिया है, हालांकि मैं अभी IDisposable जोड़ा है इस तरह ला नया उदाहरण:

clsRS232 test = new clsRS232; 
    test.openport(); 
    test.sendfunc("test"); 
    test.Dispose(); 

लेकिन वह कुछ भी नहीं बदलता है - मैं अभी भी UnauthorizedAccessExceptions के बहुत सारे मिल - और यदि अन्य पुरुष सही था (serialport श्रेणी के निपटान() केवल SerialPort.Close जिसमें ()) - ठीक है तो मुझे लगता है कि मैंने वास्तव में अपने पहले के दृष्टिकोण से कुछ भी नहीं बदला है, जहां मेरे पास फ़ंक्शन कॉल बंद था(); अपने जवाब के लिए

धन्यवाद - अभी भी आप इस तरह अपने कोड लिखना चाहिए, समाधान :)

उत्तर

6

SerialPort के बाद से लागू करता IDisposable खोजने के लिए उम्मीद कर रहा:

using(SerialPort port = new SerialPort(...)){ 
    //do what you need with the serial port here 
} 

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

संपादित

ओपी की जरूरतों के अनुसार SerialPort एक विधि की समय सीमा से अधिक समय तक खुला रहना चाहिए।

उस स्थिति में मैं पूरे तर्क को लपेटूंगा जो सीरियल पोर्ट के साथ अपनी कक्षा के अंदर है। कक्षा के निर्माता में, धारावाहिक बंदरगाह खोलें, और आपको आवश्यक संचालन करने के तरीकों को लिखें। फिर इस वर्ग को IDisposable स्वयं लागू करें, और अपने Dispose विधि के अंदर सीरियलपोर्ट का निपटान करें।

यह आपको सीरियल पोर्ट को खोलने और बंद करने और निपटाने के लिए कहां पर बेहतर नियंत्रण देगा और सीरियल पोर्ट तर्क को उचित कक्षा में लपेटें।

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

संपादित 2

आपका वर्तमान कार्यान्वयन इस तरह है:

clsRS232 test = new clsRS232; 
test.openport(); 
test.sendfunc("test"); 
test.Dispose(); 

समस्या यहां है कि अगर sendfunc किसी तरह से एक अपवाद का कारण बनता है, यह निपटारा किया जाना कभी नहीं होगा है। आप पहली जगह में IDisposable को लागू करने से लाभ क्या है, कि तुम इस तरह देखने के लिए अपने कोड बदल सकते हैं:

using(clsRS232 test = new clsRS232){ 
test.openport(); 
test.sendfunc("test"); 
} 

अब आप की गारंटी है कि Disposeusing अंदर किसी भी अपवाद की परवाह किए बिना अपने कॉम बंदरगाह के लिए बुलाया जाएगा ब्लॉक।

+0

तेज उत्तर के लिए धन्यवाद लेकिन मैं वास्तव में ऐसा नहीं कर सकता, क्योंकि मैं ने अपनी खुद की कक्षाओं में अपनी खुद की विधियों को लपेट लिया है, जिसे मैं सीरियलपोर्ट संचार के लिए उपयोग करता हूं - वे सभी एक बंदरगाह का उपयोग करते हैं, जिसे कक्षा में पहली बार बुलाया जाता है - इसलिए यदि मैं इसे ऐसा करना चाहता हूं तो मैं बंदरगाह का उपयोग करने वाली हर विधि में इस तरह के एक ब्लॉक को लिखना चाहता हूं? – Lorenz

+0

क्या आप कक्षा बनाते समय बंदरगाह को खोलना चाहते हैं, और जब सभी परिचालन किए जाते हैं तो इसे बंद करें, या आप प्रत्येक ऑपरेशन से पहले और बाद में बंदरगाह से कनेक्शन खोलना और बंद करना चाहते हैं? –

+0

पहला वाला - मेरा रैपर क्लास इसके कन्स्ट्रक्टर के माध्यम से सीरियलपोर्ट का एक उदाहरण शुरू करता है - इसके बाद इसे भेजने/प्राप्त करने के लिए कई विधियों के माध्यम से उपयोग किया जा सकता है, लेकिन एक बार जब मैं अपना खुद का करीबी() फ़ंक्शन (जिसे इस समय SerialPort.Close कहते हैं)()) मैं चाहता हूं कि सीरियलपोर्ट फिर से स्थापित होने के लिए पूरी तरह से मुक्त हो। खोलने और बंद करने से पहले और प्रत्येक ऑपरेशन के बाद काम नहीं करेगा क्योंकि उदाहरण के लिए मैंने कुछ लिखने के बाद बंदरगाह बंद कर दिया होगा और कुछ प्राप्त करने के लिए इसे फिर से खोल दिया होगा -> बफर चला जाएगा ... – Lorenz

0

ओविंद ब्रैथिन द्वारा प्रस्तावित कार्यान्वयन .NET में IDISposable पैटर्न का उपयोग करता है। उपयोग ब्लॉक के अंत में, सीरियलपोर्ट उदाहरण का निपटान फ़ंक्शन कहा जाता है, जो संबंधित अप्रबंधित संसाधनों (यानी सीरियल पोर्ट)

कॉल पोर्ट को मुक्त कर देगा। जब आप इसे रिलीज़ करना चाहते हैं तो स्वयं को रोकें।

+0

हाँ - पहले निपटान() का प्रयास किया था - दुख की बात यह है कि यह मेरे अपवादों से संबंधित कुछ भी नहीं बदलेगा:/धन्यवाद हालांकि :) – Lorenz

2

मुझे पता है कि यह बहुत पुराना है, लेकिन मैं अभी एक ही मुद्दे पर आया हूं और यह समाधान मेरे लिए काम करता है, हालांकि यह थोड़ा हैकी है। इस धागे के अनुसार why is access to com port denied? समस्या सीरियलपोर्ट क्लास में एक बग के साथ है। मैंने एक रैपर वर्ग बनाया जो केवल एक बार पोर्ट खोलता है, और एप्लिकेशन के जीवनकाल के लिए कक्षा बनाता है। Serialport तो वर्ग के निपटान में निपटान किया जाता है, लेकिन का उपयोग कर खोला जाता है निम्नलिखित:

try 
      { 
       if (OpenPort()) 
       { 
        //do your thing here ! 
       } 
       return false; 
      } 
      catch (Exception ex) 
      { 
       throw ex; 
      } 

मेरी टेस्ट (मैं इसे इस्तेमाल किया पर एक नकद दराज खोलने के लिए:

private SerialPort KickerPort { get; set; } 
    . 
    . 
    . 
private bool OpenPort() 
     { 
      //https://stackoverflow.com/questions/7219653/why-is-access-to-com-port-denied 
      //due to a bug in the SerialPort code, the serial port needs time to dispose if we used this recently and then closed 
      //therefore the "open" could fail, so put in a loop trying for a few times 
      int sleepCount = 0; 
      while (!TryOpenPort()) 
      { 
       System.Threading.Thread.Sleep(100); 
       sleepCount += 1; 
       System.Diagnostics.Debug.Print(sleepCount.ToString()); 
       if (sleepCount > 50) //5 seconds should be heaps !!! 
       { 
        throw new Exception(String.Format("Failed to open kicker USB com port {0}", KickerPort.PortName)); 
       } 
      } 
      return true; 
     } 
    private bool TryOpenPort() 
       { 
        if (!KickerPort.IsOpen) 
        { 
         try 
         { 
          KickerPort.Open(); 
          return true; 
         } 
         catch (UnauthorizedAccessException) 
         { 
          return false; 
         } 
         catch (Exception ex) 
         { 
          throw ex; 
         } 

        } 
        return true; 
       } 

इस से पुकारा जाता है एक यूएसबी किकर) मैंने पाया कि कभी-कभी यह पहली बार खोला जाता है और दूसरी बार यह नींद लूप के माध्यम से 20 बार कितनी बार

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