2012-01-16 19 views
5

मैं अपने बालों को खींचने की कोशिश कर रहा हूं जब एक धारावाहिक बंदरगाह बंद हो जाता है ताकि मैं इसे फिर से खोल सकूं। यह पता चला है कि बंदरगाह वास्तव में अनलॉक होने से पहले CloseHandle() रिटर्न देता है।धारावाहिक बंदरगाह वास्तव में बंद होने से पहले बंद हो गया है

मैं एक सीरियल पोर्ट CreateFile(FILE_FLAG_OVERLAPPED) का उपयोग करके खोलने कर रहा हूँ, एक CompletionPort CreateIoCompletionPort() का उपयोग कर के साथ संबद्ध, पढ़ने/ReadFile(), WriteFile() का उपयोग कर इसे करने के लिए लिख और CloseHandle() का उपयोग कर इसे बंद करने।

मैंने देखा है कि अगर मैं एक सीरियल बंदरगाह को जल्दी से बंद कर देता हूं और फिर से खोलता हूं, तो मुझे CreateFile() से वापस मिलता है। यह इस तथ्य के बावजूद हो रहा है कि मैं वापसी के लिए CloseHandle() की प्रतीक्षा कर रहा हूं, फिर पूरा होल्डिंग पोर्ट से वापस आने के लिए उस हैंडल से जुड़े सभी उत्कृष्ट पढ़ने/लिखने के कार्यों की प्रतीक्षा कर रहा हूं। निश्चित रूप से एक बेहतर तरीका है :)

मैं एक सीरियल पोर्ट को सिंक्रनाइज़ तरीके से कैसे बंद करूं? कृपया कोई पुनः प्रयास लूप, नींद() या कुछ अन्य सस्ते हैक्स।

संपादित करें: हो सकता है कि इसका पूरा होने वाले बंदरगाहों और FILE_FLAG_OVERLAPPED के उपयोग के साथ कुछ करना है। जब पढ़ना/लिखना संचालन पूरा होता है तो मुझे कॉलबैक मिलता है। बंदरगाह बंद करने के लिए क्या कुछ कॉलबैक है?

+0

शायद आपके विशिष्ट सीरियल पोर्ट ड्राइवर से संबंधित है। क्या आपने इसे यहां SO पर देखा है: http://stackoverflow.com/questions/2948428/reopening-serial-port-fails-if-not-closed-properly-with-closehandle –

+0

बस सुनिश्चित करने के लिए .... आप हेवन कहीं भी 'डुप्लिकेट हैंडल' इस्तेमाल नहीं किया? –

+0

मुझे यकीन नहीं है कि पूरा होने वाला बंदरगाह संबंधित है, मैंने हमेशा 'ReadFileEx' और' WriteFileEx' के साथ एपीसी कॉलबैक का उपयोग किया है। यह भी आसान है, क्योंकि एपीसी केवल तभी चलते हैं जब थ्रेड एक सतर्क प्रतीक्षा में प्रवेश करता है, इसलिए कोई क्रॉस-थ्रेड सिंक्रनाइज़ेशन समस्या नहीं होती है (केवल पुनः प्रवेश के बारे में सावधान रहें)। –

उत्तर

1

मेरा मानना ​​है कि समस्या COM पोर्ट की सेवा करने वाले ड्राइवर के साथ है। इसलिए - COM पोर्ट "वास्तव में बंद" करने के लिए कोई एपीआई नहीं होगी।

बीटीडब्ल्यू, फ़ाइल संभाल बंद करने के बाद, सभी बहिष्कार I/Os त्रुटियों के साथ पूरा करने की प्रतीक्षा करने की आवश्यकता नहीं है। उस समय CloseHandle सभी बकाया I/Os पहले से ही पूर्ण/रद्द कर दिए गए हैं, आप केवल कॉलबैक को असीमित रूप से प्राप्त करते हैं (इसे पूर्णता पोर्ट या एपीसी कतार के माध्यम से, कोई फर्क नहीं पड़ता)।

विशेष रूप से एफटीडीआई ड्राइवर (जो COM-> यूएसबी अनुकरण करते हैं) बहुत गड़बड़ होने के लिए जाने जाते हैं।

मैं केवल हैंडल बंद करने से पहले डेटा को फ्लश करने का प्रयास कर सकता हूं। आप को COM पोर्ट बंद करने से पहले सभी आई/ओएस को पूरा करने की प्रतीक्षा कर सकते हैं (यदि यह आपके मामले के लिए लागू है)। वैकल्पिक रूप से आप SetCommMask और WaitCommEvent पर कॉल कर सकते हैं ताकि यह सुनिश्चित किया जा सके कि कोई डेटा लंबित नहीं है। उम्मीद है कि यह मदद कर सकता है।

संपादित करें:

CloseHandle तुरंत (पहले यह रिटर्न) सभी लंबित मैं/ओएस फ़ाइल पर संभाल रद्द करता है?

कड़ाई से बोलते हुए - कोई

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

जब अंतिम हैंडल बंद हो जाता है तो ड्राइवर का DispatchCleanup कहा जाता है। इसे this के अनुसार सभी बकाया I/Os को रद्द करना होगा।

हालांकि एक धागा CloseHandle के भीतर है - आप सैद्धांतिक रूप से किसी अन्य थ्रेड से अन्य I/O जारी कर सकते हैं (यदि आप भाग्यशाली हैं - हैंडल अभी भी वैध होगा)। जबकि आप एक I/O फ़ंक्शन (जैसे WriteFile या आदि) के कॉल में हैं, ओएस अस्थायी रूप से ऑब्जेक्ट को संदर्भ काउंटर बढ़ाता है। यह बदले में एक और I/O शुरू कर सकता है, जिसे सीधे CloseHandle आमंत्रण द्वारा रद्द नहीं किया जाएगा।

हालांकि इस मामले में नए I/O जारी होने के तुरंत बाद हैंडल ओ/एस द्वारा बंद कर दिया जाएगा, क्योंकि ऑब्जेक्ट का संदर्भ गणना 0 पर फिर से पहुंच गई है।

ताकि इस तरह के विकृत परिदृश्य में ऐसी स्थिति हो सकती है जहां CloseHandle पर कॉल के तुरंत बाद आप फ़ाइल को दोबारा खोलने में असमर्थ हैं।

+0

मैं सीरियल पोर्ट का उपयोग कर रहा हूं जो मदरबोर्ड से निकलता है (अंतर्निहित माइक्रोसॉफ्ट ड्राइवरों का उपयोग कर)। खेलने पर यूएसबी एडाप्टर के लिए कोई COM नहीं है। डेटा फ्लश करने में समस्या यह है कि हार्डवेयर प्रवाह नियंत्रण सक्षम होने पर यह हमेशा के लिए अवरुद्ध हो सकता है। आदर्श रूप में मैं बंदरगाह वास्तव में किए जाने के बाद सभी बकाया आदेशों को बंद करना, बंदरगाह बंद करना और मेरे कार्य से वापस लौटना चाहता हूं। अगर यह सुनिश्चित करने के लिए कोई एपीआई नहीं है तो यह सब एक महत्वपूर्ण मुद्दा है। पीएस: आप कैसे जानते हैं कि 'CloseHandle() 'लौटने से पहले सभी बकाया I/Os को रद्द कर देता है? मुझे विनिर्देश में ऐसी गारंटी नहीं दिखाई दे रही है। – Gili

+0

कृपया मेरा संपादन देखें। आप 'CancelIoEx' का उपयोग करने का भी प्रयास कर सकते हैं। और, ज़ाहिर है, किसी अन्य धागे पर कोई भी I/O मत करो (मुझे आशा है कि आप इसे वैसे भी नहीं करेंगे) – valdo

+0

ठीक है, मैं बंदरगाह खोलने की कोशिश करते समय एक पुनः प्रयास लूप का उपयोग कर समाप्त हुआ। संदर्भ जानकारी के लिए धन्यवाद। – Gili

0

सुनिश्चित करें कि आपके पाठक और लेखक डिवाइस को स्पर्श करने का प्रयास करने से पहले CloseHandle() अनुरोध (संभवतः किसी अन्य थ्रेड पर) जारी करने के बाद विफल (अमान्य हैंडल के साथ) विफल हो जाएं। आप इसे एक और CreateFile जारी करने का प्रयास करने से पहले अपने सभी आईओ हैंडलिंग को साफ करने के लिए एक क्यू के रूप में उपयोग कर सकते हैं। मुझे कहना होगा कि पूरा बंदरगाहों को अनिवार्य रूप से बारोक लगता है।

+0

अच्छी चाल, लेकिन अविश्वसनीय। क्योंकि एक ही संभाल (सैद्धांतिक रूप से) पुन: उपयोग किया जा सकता है। – valdo

+0

प्लस आपके पास कोई उत्कृष्ट रीड/लिखना नहीं हो सकता है, इसलिए अब आपको इसका ट्रैक रखना होगा। – Gili

0

जब आप थ्रेड में COM पोर्ट खोलते हैं, तो ऑपरेटिंग सिस्टम I/O करने के लिए एक और छिपा धागा खोलता है। मैं एक बंदरगाह बंद करने का संकल्प करने की कोशिश कर रहा हूं। पास के रूप में मैं एक विधि बता सकता हूं जो काम कर सकता है: 1) थॉमस को खोलने वाले धागे को निलंबित करें, 2) PurgeComm() सभी I/O को रोकने के लिए और सभी पढ़ने/लिखने I/O बफर खाली करें, और 3) फिर प्रयास करें COM पोर्ट को बंद करने के लिए। एक Waitforsingleobject यह निर्धारित करने के लिए शामिल हो सकता है कि COM पोर्ट वास्तव में निलंबित होने पर धागा कब होता है। जब तक कि COM पोर्ट को पूरी तरह से बंद करने की आवश्यकता न हो, मैं COM पोर्ट को खोलने और WinProc को COM पोर्ट, थ्रेड और एप्लिकेशन को बंद करने के लिए IDM_Exit कमांड को संसाधित करने पर विचार कर रहा हूं। मैं जो चाहता था वह नहीं बल्कि एक विकल्प जिसके साथ मैं रह सकता था। मैं सीरियल पोर्ट कनेक्शन के लिए यूएसबी का उपयोग कर रहा हूं और यह सुनिश्चित नहीं करता कि इससे मुझे क्या समस्याएं आ रही हैं। मुझे पता है कि क्या आप यूएसबी सेरियल पोर्ट इंटरफ़ेस का उपयोग कर रहे हैं, आपको पिन 20 उच्च (डीटीआर) सेट करने की आवश्यकता है। पिन 20 इंटरफ़ेस को पावर करने में मदद करता है, लेकिन केवल 30ma या इससे भी अधिक प्रदान करता है। यदि यह सब काम करता है तो मैं इस पोस्ट को अपडेट कर दूंगा और आपको बता दूंगा कि मैं COM पोर्ट को बंद करने में सक्षम था या नहीं। विंडोज ने सीरियल पोर्ट ड्राइवर का गड़बड़ कर दिया है और चीजों को अव्यवस्था में छोड़ने के लिए सामग्री प्रतीत होता है!

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