पृष्ठभूमि
एक ग्राहक ने मुझे यह जानने के लिए कहा कि क्यों उनके सी # एप्लिकेशन (हम इसे सलाह देंगे जो एक सलाहकार द्वारा डिलीवर किया गया है) जो इतनी चंचल है, और इसे ठीक करें। एप्लिकेशन एक सीरियल कनेक्शन पर माप उपकरण को नियंत्रित करता है। कभी-कभी डिवाइस निरंतर रीडिंग (जो स्क्रीन पर प्रदर्शित होते हैं) प्रदान करता है, और कभी-कभी ऐप को निरंतर माप को रोकने और कमांड-प्रतिक्रिया मोड में जाने की आवश्यकता होती है।सी # - धारावाहिक बंदरगाह से कौन सा धागा पढ़ता है?
कैसे नहीं यह
निरंतर माप के लिए ऐसा करने के लिए, XXX धारावाहिक इनपुट की पृष्ठभूमि प्रसंस्करण के लिए System.Timers.Timer
उपयोग करता है। जब टाइमर आग लगती है, सी # टाइमर के ElapsedEventHandler
को अपने पूल से कुछ धागे का उपयोग करके चलाता है। XXX का इवेंट हैंडलर कई दूसरे टाइमआउट के साथ commPort.ReadLine()
को अवरुद्ध करता है, फिर सीरियल पोर्ट पर एक उपयोगी माप आने पर प्रतिनिधि को वापस कॉल करता है। यह हिस्सा ठीक काम करता है, हालांकि ...
जब रीयलटाइम माप को रोकने का समय होता है और डिवाइस को कुछ अलग करने का आदेश देता है, तो एप्लिकेशन टाइमर के Enabled = false
को सेट करके जीयूआई थ्रेड से पृष्ठभूमि प्रोसेसिंग को निलंबित करने का प्रयास करता है। बेशक, यह सिर्फ आगे की घटनाओं को रोकने के झंडे को सेट करता है, और धारावाहिक इनपुट के लिए पहले से ही इंतजार कर रहे पृष्ठभूमि थ्रेड का इंतजार जारी है। जीयूआई थ्रेड तब डिवाइस को एक कमांड भेजता है, और उत्तर पढ़ने की कोशिश करता है - लेकिन पृष्ठभूमि थ्रेड द्वारा जवाब प्राप्त होता है। अब पृष्ठभूमि धागा उलझन में आता है क्योंकि यह अपेक्षित माप नहीं है। इस बीच जीयूआई थ्रेड भ्रमित हो जाता है क्योंकि इसे अपेक्षित कमांड उत्तर प्राप्त नहीं हुआ था। अब हम जानते हैं कि क्यों XXX इतना तेज है।
संभव विधि 1
एक और इसी तरह आवेदन में, मैं के लिए मुफ्त समय से चल रहे माप एक System.ComponentModel.BackgroundWorker
धागा इस्तेमाल किया।
- कॉल धागे पर
CancelAsync
विधि, और - कॉल
commPort.DiscardInBuffer()
है, जो एक लंबित (अवरुद्ध, प्रतीक्षा में) का कारण बनता है के लिए पृष्ठभूमि सूत्र में पढ़ा अच्छी तरह पेश आना: पृष्ठभूमि प्रसंस्करण निलंबित करने के लिए मैं जीयूआई सूत्र में दो बातें कियाSystem.IO.IOException "The I/O operation has been aborted because of either a thread exit or an application request.\r\n"
फेंक दें।
पृष्ठभूमि धागे में मैं इस अपवाद को पकड़ता हूं और तत्काल साफ करता हूं, और सभी कार्य इरादे से साफ करते हैं। दुर्भाग्यवश DiscardInBuffer
किसी अन्य थ्रेड के अवरोधन में अपवाद को उत्तेजित करने के लिए कहीं भी दस्तावेज व्यवहार नहीं है, और मुझे अनियंत्रित व्यवहार पर भरोसा करने से नफरत है। यह काम करता है क्योंकि आंतरिक रूप से DiscardInBuffer
Win32 API PurgeComm को कॉल करता है, जो अवरुद्ध पढ़ने (दस्तावेज व्यवहार) को बाधित करता है।
संभव विधि 2
सीधे, एक मॉनिटर रद्द टोकन के माध्यम से, BaseClass Stream.ReadAsync
विधि का उपयोग पृष्ठभूमि आईओ दखल के समर्थित तरह से इस्तेमाल करते हैं।
क्योंकि प्राप्त होने वाले पात्रों की संख्या परिवर्तनीय (एक नई लाइन द्वारा समाप्त) है, और फ्रेमवर्क में ReadAsyncLine
विधि मौजूद नहीं है, मुझे नहीं पता कि यह संभव है या नहीं। मैं प्रत्येक चरित्र को व्यक्तिगत रूप से संसाधित कर सकता हूं लेकिन एक प्रदर्शन हिट लेगा (धीमी मशीनों पर काम नहीं कर सकता है, बशर्ते कि लाइन-टर्मिनेशन बिट पहले ही फ्रेमवर्क के भीतर सी # में कार्यान्वित नहीं किया गया हो)।
संभव विधि 3
एक ताला बनाएँ "मैं सीरियल पोर्ट मिल गया है"। बंदरगाह से इनपुट को पढ़ता, लिखता या छोड़ता नहीं है जब तक कि उनके पास लॉक न हो (पृष्ठभूमि थ्रेड में अवरुद्ध अवरोध को दोहराएं)। बहुत अधिक ओवरहेड के बिना स्वीकार्य जीयूआई प्रतिक्रिया के लिए पृष्ठभूमि थ्रेड में टाइमआउट मानों को 1/4 सेकेंड तक चिपकाएं।
प्रश्न
किसी को भी इस समस्या से निपटने के लिए एक सिद्ध समाधान है? धारावाहिक बंदरगाह की पृष्ठभूमि प्रक्रिया को साफ तरीके से कैसे रोक सकता है? मैंने गुमराह किया है और सी # SerialPort
कक्षा को झुकाव वाले लेखों के दर्जनों लेख पढ़े हैं, लेकिन उन्हें कोई अच्छा समाधान नहीं मिला है।
अग्रिम धन्यवाद! SerialPort
कक्षा के लिए
आप वास्तविक समस्या पर ध्यान केंद्रित नहीं कर रहे हैं, यह System.Timers.Timer है। इससे छुटकारा पाएं और इसके बजाय एक सिंक्रोनस टाइमर का उपयोग करें। –
क्षमा करें हंस, मैं पालन नहीं करता हूं। संभव विधियों में से कोई भी नहीं 1-3 सिस्टम का उपयोग करें। टिमर्स। टिमर; आप क्या सुझाव दे रहे हैं –