एम्बेडेड सिस्टम में व्यवधान का उपयोग करते समय वैश्विक चर से बचना


13

क्या एक एम्बेडेड सिस्टम के लिए एक ISR और बाकी प्रोग्राम के बीच संचार को लागू करने का एक अच्छा तरीका है जो वैश्विक चर से बचा जाता है?

ऐसा लगता है कि सामान्य पैटर्न में एक वैश्विक चर है जो आईएसआर और बाकी कार्यक्रम के बीच साझा किया जाता है और एक ध्वज के रूप में उपयोग किया जाता है, लेकिन वैश्विक चर का यह उपयोग अनाज के खिलाफ जाता है। मैंने avr-libc शैली ISRs का उपयोग करते हुए एक सरल उदाहरण शामिल किया है:

volatile uint8_t flag;

int main() {
    ...

    if (flag == 1) {
        ...
    }
    ...
}

ISR(...) {
    ...
    flag = 1;
    ...
}

मैं दूर से नहीं देख सकता कि अनिवार्य रूप से एक स्कूपिंग मुद्दा क्या है; ISR और कार्यक्रम के बाकी हिस्सों द्वारा सुलभ कोई भी चर निश्चित रूप से वैश्विक होना चाहिए, निश्चित रूप से? इसके बावजूद, मैंने अक्सर लोगों को यह कहते देखा है कि "वैश्विक वैरिएबल आईएसआर और बाकी प्रोग्राम के बीच संचार को लागू करने का एक तरीका है" (जोर मेरा), जो कि लगता है कि अन्य तरीके हैं; अगर अन्य तरीके हैं, तो वे क्या हैं?



1
यह जरूरी नहीं है कि बाकी के सभी कार्यक्रम का उपयोग हो; यदि आपने चर को स्थिर घोषित किया है, तो केवल वह फ़ाइल जिसमें चर घोषित किया गया था, उसे देखेगा। यह चर के लिए बिल्कुल भी मुश्किल नहीं है जो पूरे एक फ़ाइल के भीतर दिखाई दे रहे हैं, लेकिन बाकी कार्यक्रम नहीं है और यह मदद कर सकता है।
दिबोसको

1
बगल में, ध्वज को अस्थिर घोषित किया जाना चाहिए, क्योंकि आप इसे सामान्य प्रोग्राम प्रवाह के बाहर उपयोग / बदल रहे हैं। यह कंपाइलर को किसी भी रीड / राइट को फ्लैग करने और वास्तविक रीड / राइट ऑपरेशन करने के लिए ऑप्टिमाइज़ नहीं करने पर मजबूर करता है।
अगली

@ अगली-हैक हां यह बिल्कुल सही है, क्षमा करें मैं बस एक उदाहरण के साथ जल्दी आने की कोशिश कर रहा था।

जवाबों:


18

ऐसा करने के लिए एक वास्तविक मानक तरीका है (सी प्रोग्रामिंग मानकर):

  • इंटरप्ट / आईएसआर निम्न स्तर के होते हैं और इसलिए इसे केवल हार्डवेयर से संबंधित ड्राइवर के अंदर लागू किया जाना चाहिए जो रुकावट उत्पन्न करता है। उन्हें कहीं और नहीं बल्कि उस ड्राइवर के अंदर होना चाहिए।
  • आईएसआर के साथ सभी संचार केवल चालक और चालक द्वारा किया जाता है। यदि कार्यक्रम के अन्य हिस्सों को उस जानकारी तक पहुंच की आवश्यकता होती है, तो उसे सेटर / गेट्टर फ़ंक्शन या समान के माध्यम से चालक से इसका अनुरोध करना होगा।
  • आपको "वैश्विक" चर घोषित नहीं करना चाहिए। बाहरी लिंकेज के साथ वैश्विक अर्थ फ़ाइल गुंजाइश चर। वह है: चर जिन्हें externकीवर्ड के साथ या गलती से बुलाया जा सकता है।
  • इसके बजाय, ड्राइवर के अंदर निजी एनकैप्सुलेशन को मजबूर करने के लिए, ड्राइवर और आईएसआर के बीच साझा किए गए ऐसे सभी चर घोषित किए जाएंगे static। ऐसा वैरिएबल वैश्विक नहीं है, बल्कि उस फ़ाइल तक ही सीमित है जहाँ उसे घोषित किया गया है।
  • कंपाइलर ऑप्टिमाइज़ेशन समस्याओं को रोकने के लिए, ऐसे वेरिएबल्स को भी घोषित किया जाना चाहिए volatile। नोट: यह परमाणु प्रवेश नहीं देता है या फिर से प्रवेश नहीं देता है!
  • चालक को ISR वैरिएबल लिखने की स्थिति में, पुन: प्रवेश तंत्र के कुछ तरीके की आवश्यकता होती है। उदाहरण: इंटरप्ट डिसेबल, ग्लोबल इंटरप्ट मास्क, सेमाफोर / म्यूटेक्स या गारंटीकृत एटॉमिक रीड।

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

सेटर / फ़ंक्शंस का उपयोग करने पर काउंटर-तर्क बढ़ा हुआ ओवरहेड (और अतिरिक्त कोड) होने पर आप क्या कहेंगे? मैं खुद इस पर जा रहा हूं, हमारे 8 बिट एम्बेडेड उपकरणों के लिए कोड मानकों के बारे में सोच रहा हूं।
लेरॉयल

2
@ Leroy105 सी भाषा ने अब तक अनंत काल के लिए इनलाइन कार्यों का समर्थन किया है। यद्यपि यहां तक ​​कि उपयोग भी inlineअप्रचलित हो रहा है, क्योंकि कंपाइलर अनुकूलन कोड में अधिक स्मार्ट और स्मार्ट हो जाते हैं। मैं कहूंगा कि ओवरहेड के बारे में चिंता करना "पूर्व-परिपक्व अनुकूलन" है - ज्यादातर मामलों में ओवरहेड मायने नहीं रखता है, अगर यह मशीन कोड में भी मौजूद है।
लंडिन

2
कहा जा रहा है कि, ISR ड्राइवरों को लिखने के मामले में, सभी प्रोग्रामर का लगभग 80-90% (यहाँ अतिशयोक्ति नहीं) हमेशा उनमें कुछ गलत हो जाता है। परिणाम सूक्ष्म कीड़े हैं: गलत तरीके से साफ किए गए झंडे, लापता अस्थिर, दौड़ की स्थिति, घटिया वास्तविक समय प्रदर्शन, स्टैक ओवरफ्लो आदि से गलत संकलक अनुकूलन। यदि चालक के अंदर आईएसआर ठीक से समझाया नहीं गया है, तो इस तरह के सूक्ष्म कीड़े होने की संभावना है। और बढ़ गया। परिधीय हित की चीजों के बारे में चिंता करने से पहले बग फ्री-ड्राइवर लिखने पर ध्यान दें, जैसे कि सेटर / गेटर्स एक छोटे से ओवरहेड का परिचय देते हैं।
लंडिन

10
वैश्विक चर का यह उपयोग अनाज के खिलाफ मेरे पास जाता है

यही असली समस्या है। इससे छुटकारा मिले।

अब घुटने से पहले झटका देने वाले तुरंत इस बारे में शेख़ी करते हैं कि यह अशुद्ध कैसे है, मुझे इस योग्य बनाना है कि थोड़ा। वैश्विक चर का अधिक उपयोग करने में निश्चित रूप से खतरा है। लेकिन, वे दक्षता भी बढ़ा सकते हैं, जो कभी-कभी छोटे संसाधन-सीमित प्रणालियों में मायने रखती है।

कुंजी यह सोचने के लिए है कि आप कब उनका यथोचित उपयोग कर सकते हैं और अपने आप को परेशानी में डालने की संभावना नहीं है, बनाम बग बस होने की प्रतीक्षा कर रहा है। हमेशा ट्रेडऑफ होते हैं। जबकि आम तौर पर बाधा और अग्रभूमि कोड के बीच संवाद स्थापित करने के लिए वैश्विक चर से परहेज, एक undertandable दिशानिर्देश है, यह लेने के एक धर्मों चरम पर ज्यादातर अन्य दिशा-निर्देशों की तरह, प्रतिकूल है।

कुछ उदाहरण जहां मैं कभी-कभी बाधा और अग्रभूमि कोड के बीच जानकारी पारित करने के लिए वैश्विक चर का उपयोग करता हूं:

  1. घड़ी घड़ी काउंटर सिस्टम घड़ी बाधा द्वारा प्रबंधित। मेरे पास आमतौर पर एक आवधिक घड़ी अवरोध है जो हर 1 एमएस चलता है। यह अक्सर सिस्टम में विभिन्न समय के लिए उपयोगी होता है। इस जानकारी को रुकावट की दिनचर्या से बाहर निकालने का एक तरीका जहां बाकी प्रणाली इसका उपयोग कर सकती है वह है एक वैश्विक घड़ी टिक काउंटर। इंटरप्ट रूटीन हर घड़ी टिक को बढ़ाता है। फोरग्राउंड कोड किसी भी समय काउंटर को पढ़ सकता है। अक्सर मैं इसे 10 एमएस, 100 एमएस और यहां तक ​​कि 1 सेकंड के टिक के लिए भी करता हूं।

    मुझे यकीन है कि 1 एमएस, 10 एमएस, और 100 एमएस टिक एक शब्द आकार के हैं जो एक एकल परमाणु संचालन में पढ़ा जा सकता है। यदि उच्च स्तर की भाषा का उपयोग कर रहे हैं, तो संकलक को बताना सुनिश्चित करें कि ये चर असिंक्रोनस रूप से बदल सकते हैं। सी में, आप उन्हें बाहरी अस्थिर घोषित करते हैं , उदाहरण के लिए। बेशक यह एक ऐसी चीज है जो डिब्बाबंद हो जाती है, जिसमें फ़ाइल शामिल होती है, इसलिए आपको हर प्रोजेक्ट के लिए यह याद रखने की जरूरत नहीं है।

    मैं कभी-कभी 1 एस टिक काउंटर को कुल बीता हुआ समय काउंटर बना देता हूं, इसलिए उस 32 बिट्स को चौड़ा करें। मेरे द्वारा उपयोग किए जाने वाले कई छोटे माइक्रो पर एक भी परमाणु संचालन में नहीं पढ़ा जा सकता है, इसलिए यह वैश्विक नहीं है। इसके बजाय, एक रूटीन प्रदान किया जाता है जो बहु-शब्द मान को पढ़ता है, पठन के बीच संभावित अपडेट से संबंधित है, और परिणाम देता है।

    बेशक वहाँ सकता है दिनचर्या, छोटे 1 एमएस, 10 एमएस, आदि मिल भी काउंटर टिक गया है। हालाँकि, यह वास्तव में आपके लिए बहुत कम है, एक शब्द को पढ़ने के स्थान पर बहुत सारे निर्देश जोड़ता है, और एक अन्य कॉल स्टैक स्थान का उपयोग करता है।

    नकारात्मक पक्ष क्या है? मुझे लगता है कि कोई ऐसा टाइपो बना सकता है जो गलती से काउंटरों में से एक को लिखता है, जो तब सिस्टम में अन्य समय को गड़बड़ कर सकता है। जानबूझकर एक काउंटर पर लिखने का कोई मतलब नहीं होगा, इसलिए इस तरह के बग को टाइपो की तरह कुछ अनजाने में होना चाहिए। बहुत संभावना लगता है। मुझे याद नहीं है कि कभी भी 100 से अधिक छोटे माइक्रोकंट्रोलर परियोजनाओं में हो रहा हो।

  2. अंतिम फ़िल्टर किए गए और ए / डी मूल्यों को समायोजित किया। एक सामान्य बात यह है कि ए / डी से रीडिंग को बाधित करना एक नियमित दिनचर्या है। मैं आमतौर पर आवश्यक से अधिक तेजी से एनालॉग मूल्यों को पढ़ता हूं, फिर थोड़ा कम-पास फ़िल्टरिंग लागू करता हूं। अक्सर स्केलिंग और ऑफसेट भी होते हैं जो लागू होते हैं।

    उदाहरण के लिए, ए / डी 24 वी आपूर्ति को मापने के लिए वोल्टेज डिवाइडर के 0 से 3 वी आउटपुट को पढ़ सकता है। कई रीडिंग को कुछ फ़िल्टरिंग के माध्यम से चलाया जाता है, फिर स्केल किया जाता है ताकि अंतिम मूल्य मिलिवोल्ट्स में हो। यदि आपूर्ति 24.015 V पर है, तो अंतिम मूल्य 24015 है।

    सिस्टम के बाकी हिस्से में आपूर्ति वोल्टेज का संकेत देने वाला लाइव अपडेटेड वैल्यू दिखता है। यह न तो पता है और न ही जब वास्तव में अद्यतन किया जाता है, तब तक देखभाल करने की आवश्यकता होती है, खासकर जब से इसे कम पास फिल्टर की तुलना में अधिक बार अपडेट किया जाता है।

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


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

3
@ Leroy105 समस्या "आतंकवादियों" जानबूझकर वैश्विक चर का दुरुपयोग नहीं है। नेमस्पेस प्रदूषण बड़ी परियोजनाओं में एक समस्या हो सकती है, लेकिन इसे अच्छे नामकरण से हल किया जा सकता है। नहीं, असली समस्या प्रोग्रामर की है जो वैश्विक चर का उपयोग करने का प्रयास कर रहा है, लेकिन ऐसा सही ढंग से करने में विफल है। या तो क्योंकि वे सभी ISRs के साथ मौजूद दौड़ की स्थिति को महसूस नहीं करते हैं, या क्योंकि वे अनिवार्य सुरक्षा तंत्र के कार्यान्वयन में गड़बड़ी करते हैं, या बस इसलिए कि वे कोड भर में वैश्विक चर का उपयोग करते हैं, तंग युग्मन बनाते हैं और अपठनीय कोड।
लुंडिन

आपकी बातें मान्य हैं ओलिन, लेकिन इन उदाहरणों में भी, के extern int ticks10msसाथ प्रतिस्थापित करने inline int getTicks10ms()से संकलित असेंबली में बिल्कुल कोई फर्क नहीं पड़ेगा, जबकि दूसरी तरफ यह कार्यक्रम के अन्य हिस्सों में गलती से अपना मूल्य बदल देगा, और आपको भी अनुमति देगा इस कॉल को "हुक" करने का एक तरीका (जैसे इकाई परीक्षण के दौरान समय का मज़ाक उड़ाने के लिए, इस चर तक पहुंच को लॉग करने के लिए, या जो भी हो)। यहां तक ​​कि अगर आप तर्क देते हैं कि एक सैन प्रोग्रामर के इस चर को शून्य में बदलने की संभावना है, तो इनलाइन गेट्टर की कोई कीमत नहीं है।
ग्रो

@Groo: यह केवल तभी सच है जब आप एक ऐसी भाषा का उपयोग कर रहे हैं जो inlining फ़ंक्शन का समर्थन करती है, और इसका मतलब है कि गेटर फ़ंक्शन की परिभाषा सभी को दिखाई देने की आवश्यकता है। वास्तव में उच्च स्तरीय भाषा का उपयोग करते समय, मैं गेटटर फ़ंक्शंस का अधिक उपयोग करता हूं और वैश्विक चर कम। असेंबली में, एक ग्लोबल वेरिएबल की वैल्यू को हथियाने की तुलना में यह बहुत आसान है कि एक गेटर फ़ंक्शन के साथ परेशान किया जाए।
ओलिन लेथ्रोप

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

2

कोई विशेष व्यवधान एक वैश्विक संसाधन होगा। कभी-कभी, हालांकि, एक ही कोड को साझा करने में कई व्यवधान होना उपयोगी हो सकता है। उदाहरण के लिए, एक प्रणाली में कई UARTs हो सकते हैं, जिनमें से सभी को समान भेजने / प्राप्त तर्क का उपयोग करना चाहिए।

संभाल करने के लिए एक अच्छा तरीका है कि एक बाधा वस्तु में इंटरप्ट हैंडलर, या पॉइंटर्स द्वारा उपयोग की जाने वाली चीजों को रखना है, और फिर वास्तविक हार्डवेयर इंटरप्ट हैंडलर कुछ इस तरह हैं:

void UART1_handler(void) { uart_handler(&uart1_info); }
void UART2_handler(void) { uart_handler(&uart2_info); }
void UART3_handler(void) { uart_handler(&uart3_info); }

ऑब्जेक्ट्स uart1_info, uart2_infoइत्यादि ग्लोबल वैरिएबल होंगे, लेकिन वे एकमात्र ग्लोबल वैरिएबल होंगे, जिनका उपयोग रुकावट संचालकों द्वारा किया जाता है। बाकी सब जो हैंडलर छूने जा रहे हैं, उन्हें उन लोगों के हाथों में सौंप दिया जाएगा।

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

if (foo->timer)
  foo->timer--;

लिखो:

uint32_t was_timer;
was_timer = foo->timer;
if (was_timer)
{
  was_timer--;
  foo->timer = was_timer;
}

पूर्व दृष्टिकोण को पढ़ना और समझना आसान हो सकता है, लेकिन बाद की तुलना में कम कुशल होगा। क्या यह एक चिंता है कि आवेदन पर निर्भर करेगा।


0

यहां तीन विचार दिए गए हैं:

एक एकल फ़ाइल के लिए गुंजाइश को सीमित करने के लिए ध्वज चर को स्थिर घोषित करें।

ध्वज चर को निजी बनाएं और ध्वज मान तक पहुंचने के लिए गेटटर और सेटर फ़ंक्शन का उपयोग करें।

एक सिग्नल चर का उपयोग करें जैसे कि फ्लैग वेरिएबल के बजाय सेमाफोर। ISR सेमाफोर को सेट / पोस्ट करेगा।


0

एक व्यवधान (यानी, वेक्टर जो आपके हैंडलर को इंगित करता है) एक वैश्विक संसाधन है। तो भी अगर आप ढेर पर या ढेर पर कुछ चर का उपयोग करते हैं:

volatile bool *flag;  // must be initialized before the interrupt is enabled

ISR(...) {
    *flag = true;
}

या 'वर्चुअल' फ़ंक्शन के साथ ऑब्जेक्ट-ओरिएंटेड कोड:

HandlerObject *obj;

ISR(...) {
    obj->handler_function(obj);
}

... उस दूसरे डेटा तक पहुंचने के लिए पहले चरण में एक वास्तविक वैश्विक (या कम से कम स्थिर) चर शामिल होना चाहिए।

ये सभी तंत्र एक अप्रत्यक्ष जोड़ते हैं, इसलिए यह आमतौर पर नहीं किया जाता है यदि आप अंतःक्रियात्मक हैंडलर से अंतिम चक्र को निचोड़ना चाहते हैं।


आपको ध्वज को वाष्पशील int * घोषित करना चाहिए।
अगली

0

मैं इस समय Cortex M0 / M4 के लिए कोडिंग कर रहा हूं और जिस दृष्टिकोण का हम C ++ में उपयोग कर रहे हैं (कोई C ++ टैग नहीं है, इसलिए यह उत्तर ऑफ-टॉपिक हो सकता है) निम्नलिखित है:

हम एक ऐसे वर्ग का उपयोग करते हैं CInterruptVectorTable, जिसमें सभी व्यवधान सेवा दिनचर्याएँ होती हैं जो नियंत्रक के वास्तविक व्यवधान वेक्टर में संग्रहीत होती हैं:

#pragma location = ".intvec"
extern "C" const intvec_elem __vector_table[] =
{
  { .__ptr = __sfe( "CSTACK" ) },           // 0x00
  __iar_program_start,                      // 0x04

  CInterruptVectorTable::IsrNMI,            // 0x08
  CInterruptVectorTable::IsrHardFault,      // 0x0C
  //[...]
}

कक्षा CInterruptVectorTableमें रुकावट वैक्टर का एक अमूर्त भाग होता है, इसलिए आप रनटाइम के दौरान विभिन्न कार्यों को बीच में रोक सकते हैं।

उस वर्ग का इंटरफ़ेस इस तरह दिखता है:

class CInterruptVectorTable  {
public :
    typedef void (*IsrCallbackfunction_t)(void);                      

    enum InterruptId_t {
        INTERRUPT_ID_NMI,
        INTERRUPT_ID_HARDFAULT,
        //[...]
    };

    typedef struct InterruptVectorTable_t {
        IsrCallbackfunction_t IsrNMI;
        IsrCallbackfunction_t IsrHardFault;
        //[...]
    } InterruptVectorTable_t;

    typedef InterruptVectorTable_t* PinterruptVectorTable_t;


public :
    CInterruptVectorTable(void);
    void SetIsrCallbackfunction(const InterruptId_t& interruptID, const IsrCallbackfunction_t& isrCallbackFunction);

private :

    static void IsrStandard(void);

public :
    static void IsrNMI(void);
    static void IsrHardFault(void);
    //[...]

private :

    volatile InterruptVectorTable_t virtualVectorTable;
    static volatile CInterruptVectorTable* pThis;
};

आपको उन फ़ंक्शन को बनाने की आवश्यकता है जो वेक्टर टेबल में संग्रहीत हैं staticक्योंकि नियंत्रक एक- thisपॉइंटर प्रदान नहीं कर सकता है क्योंकि वेक्टर टेबल ऑब्जेक्ट नहीं है। तो उस समस्या को हल करने के लिए हमारे पास स्थिर- pThisसूचक है CInterruptVectorTable। स्थैतिक व्यवधान कार्यों में से एक में प्रवेश करने पर, यह pThisएक वस्तु के सदस्यों तक पहुंच प्राप्त करने के लिए -pointer तक पहुंच सकता है CInterruptVectorTable


अब प्रोग्राम में, आप SetIsrCallbackfunctionकिसी फ़ंक्शन को फ़ंक्शन पॉइंटर प्रदान करने के लिए उपयोग कर सकते हैं staticजिसे एक रुकावट होने पर बुलाया जाना है। पॉइंटर्स को स्टोर किया जाता है InterruptVectorTable_t virtualVectorTable

और एक रुकावट फ़ंक्शन का कार्यान्वयन इस तरह दिखता है:

void CInterruptVectorTable::IsrNMI(void) {
    pThis->virtualVectorTable.IsrNMI(); 
}

तो यह एक staticअन्य वर्ग (जो हो सकता है private) की एक विधि को कॉल करेगा , जो तब static thisउस ऑब्जेक्ट के सदस्य-चर तक पहुंच प्राप्त करने के लिए एक और -पॉइंट कर सकता है (केवल एक)।

मुझे लगता है कि आप IInterruptHandlerवस्तुओं को पॉइंटर्स की तरह बना और इंटरफ़ेस कर सकते हैं, इसलिए आपको static thisउन सभी वर्गों में -pointer की आवश्यकता नहीं है । (शायद हम कोशिश करते हैं कि हमारी वास्तुकला के अगले पुनरावृत्ति में)

अन्य दृष्टिकोण हमारे लिए ठीक काम करता है, क्योंकि एक बाधा हैंडलर को लागू करने के लिए अनुमति दी गई एकमात्र वस्तुएं हार्डवेयर अमूर्त परत के अंदर होती हैं, और हमारे पास आमतौर पर प्रत्येक हार्डवेयर ब्लॉक के लिए केवल एक ही वस्तु होती है, इसलिए यह static this-ऑइंटर्स के साथ ठीक काम करता है। और हार्डवेयर एब्स्ट्रेक्शन लेयर इंटरप्ट को एक और एब्सट्रैक्ट प्रदान करता है, जिसे ICallbackतब हार्डवेयर के ऊपर डिवाइस लेयर में लागू किया जाता है।


क्या आप वैश्विक डेटा का उपयोग करते हैं? सुनिश्चित करें कि आप करते हैं, लेकिन आप अधिकांश वैश्विक डेटा को- thisपॉइंटर्स और इंटरप्ट फ़ंक्शंस की तरह निजी बना सकते हैं ।

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


1
"तो आप रनवे के दौरान विभिन्न कार्यों को बाधित वैक्टर से बांध सकते हैं" यह एक बुरे विचार की तरह लगता है। कार्यक्रम की "चक्रीय जटिलता" सिर्फ छत के माध्यम से जाएगी। सभी उपयोग-केस संयोजनों का परीक्षण करना होगा ताकि न तो समय हो और न ही स्टैक उपयोग टकराव हो। बहुत सीमित उपयोगिता वाले IMO वाले फीचर के लिए बहुत सारे सिर में दर्द। (जब तक आपके पास बूटलोडर मामला है, यह एक और कहानी है) कुल मिलाकर यह मेटा प्रोग्रामिंग की खुशबू आ रही है।
लुंडिन

@ लुंडिन मैं वास्तव में आपकी बात नहीं देखता। हम इसका उपयोग उदाहरण के लिए एसपीआई इंटरप्ट हैंडलर के लिए डीएमए इंटरप्ट करने के लिए करते हैं, यदि डीएमए एसपीआई के लिए उपयोग में है और यूएआर इंटरप्ट हैंडलर के लिए है तो यह यूएआरटी के लिए उपयोग में है। दोनों हैंडलर का परीक्षण किया जाना है, निश्चित है, लेकिन समस्या नहीं है। और इसका निश्चित रूप से मेटा प्रोग्रामिंग से कोई लेना-देना नहीं है।
शस्त्रागार

डीएमए एक बात है, रुकावट वैक्टर का रन-टाइम असाइनमेंट पूरी तरह से कुछ और है। रन-टाइम में डीएमए ड्राइवर सेटअप को परिवर्तनशील होने देना समझ में आता है। एक वेक्टर टेबल, इतना नहीं।
लंडिन

@ लुंडिन मुझे लगता है कि हमारे पास उस पर अलग-अलग विचार हैं, हम इसके बारे में एक चैट शुरू कर सकते हैं, क्योंकि मैं अभी भी इसके साथ आपकी समस्या नहीं देखता हूं - इसलिए यह हो सकता है कि मेरा जवाब इतना बुरी तरह से लिखा गया हो, कि पूरी अवधारणा गलत समझी गई हो।
शस्त्रागार
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.