- सेमाफोर क्या है?
- FreeRTOS में सेमाफोर का उपयोग कैसे करें?
- सेमीफोर कोड स्पष्टीकरण
- सर्किट आरेख
- म्यूटेक्स क्या है?
- FreeRTOS में म्यूटेक्स का उपयोग कैसे करें?
- म्यूटेक्स कोड स्पष्टीकरण
पिछले ट्यूटोरियल में, हमने Arduino के साथ FreeRTOS की मूल बातें और FreeRTOS Lduino में क्यू कर्नेल ऑब्जेक्ट को कवर किया है। अब, इस तीसरे FreeRTOS ट्यूटोरियल में, हम FreeRTOS और इसके अग्रिम APIs के बारे में अधिक जानेंगे, जिससे आप मल्टी-टास्किंग प्लेटफ़ॉर्म को अधिक गहराई से समझ सकते हैं।
सेमाफोर और म्यूटेक्स (म्यूचुअल एक्सक्लूज़न) कर्नेल ऑब्जेक्ट्स हैं जिनका उपयोग सिंक्रनाइज़ेशन, संसाधन प्रबंधन और संसाधनों को भ्रष्टाचार से बचाने के लिए किया जाता है। इस ट्यूटोरियल के पहले भाग में, हम सेमीफोर के पीछे के विचार को देखेंगे कि इसका उपयोग कैसे और कहाँ किया जाए। दूसरे हाफ में हम म्यूटेक्स के साथ बने रहेंगे ।
सेमाफोर क्या है?
पिछले ट्यूटोरियल में, हमने कार्य प्राथमिकताओं के बारे में चर्चा की है और यह भी जाना है कि उच्च प्राथमिकता वाला कार्य कम प्राथमिकता वाले कार्य को पूर्व-प्राथमिकता देता है, इसलिए उच्च प्राथमिकता वाले कार्य के निष्पादन के दौरान संभावना हो सकती है कि डेटा भ्रष्टाचार कम प्राथमिकता वाले कार्य में हो सकता है क्योंकि यह अभी तक निष्पादित नहीं किया गया है और डेटा लगातार इस कार्य के लिए एक सेंसर से आ रहा है जो डेटा हानि और पूरे एप्लिकेशन की खराबी का कारण बनता है।
इसलिए, संसाधनों को डेटा हानि से बचाने की आवश्यकता है और यहां सेमाफोर एक महत्वपूर्ण भूमिका निभाता है।
सेमाफोर एक संकेतन तंत्र है जिसमें एक प्रतीक्षा स्थिति में एक कार्य निष्पादन के लिए एक अन्य कार्य द्वारा संकेत दिया जाता है। दूसरे शब्दों में, जब एक टास्क 1 ने अपना काम पूरा कर लिया है, तो वह एक झंडा दिखाएगा या 1 से झंडा बढ़ाएगा और फिर इस झंडे को एक अन्य कार्य (टास्क 2) प्राप्त होता है, जिसमें दिखाया गया है कि यह अब अपना काम कर सकता है। जब task2 ने अपना काम पूरा किया तब ध्वज 1 से कम हो जाएगा।
तो, मूल रूप से, यह एक "दे" और "टेक" तंत्र है और सेमाफोर एक पूर्णांक चर है जो संसाधनों तक पहुंच को सिंक्रनाइज़ करने के लिए उपयोग किया जाता है।
FreeRTOS में सेमाफोर के प्रकार:
सेमाफोर दो प्रकार का होता है।
- बाइनरी सेमाफोर
- सेमाफोर की गिनती
1. बाइनरी सेमाफोर: इसमें दो पूर्णांक मान 0 और 1. यह कुछ हद तक कतार के समान है। उदाहरण के लिए, हमारे पास दो कार्य, टास्क 1 और टास्क 2 हैं। टास्क 1 टास्क 2 को डेटा भेजता है इसलिए टास्क 2 लगातार क्यू आइटम को चेक करता है यदि 1 है, तो वह डेटा को पढ़ सकता है और इसे तब तक इंतजार करना होगा जब तक यह 1 नहीं हो जाता। 1 डेटा लेने के बाद, कार्य 2 कतार को घटाता है और इसे 0 करता है। इसका मतलब है कि कार्य फिर से टास्क 2 में डेटा भेज सकते हैं।
उपरोक्त उदाहरण से, यह कहा जा सकता है कि बाइनरी सेमाफोर का उपयोग कार्यों के बीच या कार्यों और बीच में सिंक्रनाइज़ेशन के लिए किया जाता है।
2. गणना सेमाफोर: इसमें 0 से अधिक मान होते हैं और लंबाई की कतार के बारे में अधिक से अधिक सोचा जा सकता है। इस सेमाफोर का उपयोग गिनती की घटनाओं के लिए किया जाता है। इस उपयोग परिदृश्य में, एक ईवेंट हैंडलर प्रत्येक बार किसी ईवेंट को घटित करने के लिए (सेमाफोर काउंट वैल्यू बढ़ाकर) एक 'सेमाफोर' देगा, और एक हैंडलर टास्क एक सेमाफोर को हर बार 'ईवेंट' को प्रोसेस करने (सेमाफोर काउंट वैल्यू को घटाते हुए) लेगा। ।
गणना मूल्य, इसलिए, हुई घटनाओं की संख्या और संसाधित होने वाली संख्या के बीच का अंतर है।
अब, देखते हैं कि हमारे FreeRTOS कोड में सेमाफोर का उपयोग कैसे करें।
FreeRTOS में सेमाफोर का उपयोग कैसे करें?
FreeRTOS एक semaphore बनाने, एक semaphore लेने और एक semaphore देने के लिए विभिन्न APIs का समर्थन करता है।
अब, एक ही कर्नेल ऑब्जेक्ट के लिए दो प्रकार के API हो सकते हैं। अगर हमें एक ISR से सेमाफोर देना है, तो सामान्य सेमाफोर एपीआई का उपयोग नहीं किया जा सकता है। आपको बाधित संरक्षित एपीआई का उपयोग करना चाहिए।
इस ट्यूटोरियल में, हम बाइनरी सेमाफोर का उपयोग करेंगे क्योंकि इसे समझना और लागू करना आसान है। जैसा कि बाधित कार्यक्षमता का उपयोग यहां किया जाता है, आपको ISR फ़ंक्शन में बाधित संरक्षित एपीआई का उपयोग करने की आवश्यकता होती है। जब हम किसी कार्य को एक रुकावट के साथ सिंक्रनाइज़ कर रहे हैं, तो इसका मतलब है कि ISR के ठीक बाद कार्य को रनिंग स्थिति में लाना।
एक सेमाफोर बनाना:
किसी भी कर्नेल ऑब्जेक्ट का उपयोग करने के लिए, हमें पहले इसे बनाना होगा। बाइनरी सेमाफोर बनाने के लिए, vSemaphoreCreateBinary () का उपयोग करें ।
यह API कोई पैरामीटर नहीं लेता है और SemaphoreHandle_t प्रकार का एक चर लौटाता है। एक वैश्विक चर नाम sema_v को सेमीफोर स्टोर करने के लिए बनाया गया है।
सेमीफोरहैंडल_ट सेमी_एवी; sema_v = xSemaphoreCreateBinary ();
एक सेमाफोर देते हुए:
एक सेमाफोर देने के लिए, दो संस्करण हैं- एक रुकावट के लिए और दूसरा सामान्य कार्य के लिए।
- xSemaphoreGive (): यह API केवल एक तर्क लेता है जो कि semaph_ का वैरिएबल नाम है जैसे कि sema_v जैसा कि ऊपर दिया गया है, एक सेमाफोर बनाते समय। इसे किसी भी सामान्य कार्य से बुलाया जा सकता है जिसे आप सिंक्रनाइज़ करना चाहते हैं।
- xSemaphoreGiveFromISR (): यह xSemaphoreGive () का बाधित संरक्षित एपीआई संस्करण है। जब हमें एक ISR और सामान्य कार्य को सिंक्रनाइज़ करने की आवश्यकता होती है, तो xSemaphoreGiveFromISR () का उपयोग ISR फ़ंक्शन से किया जाना चाहिए।
एक सेमाफोर लेना:
एक सेमाफोर लेने के लिए, एपीआई फ़ंक्शन xSemaphoreTake () का उपयोग करें । यह API दो पैरामीटर लेता है।
xSemaphoreTake (SemaphoreHandle_t xSemaphore, TickType_t xTicksToWait);
xSemaphore: हमारे मामले में लिए जाने वाले सेमाफोर का नाम sema_v है।
xTicksToWait: यह वह अधिकतम समय है जब टास्क उपलब्ध होने के लिए ब्लॉक की अवस्था में कार्य प्रतीक्षा करेगा। हमारी परियोजना में, हम xTicksToWait को portMAX_DELAY में सेट करेंगे ताकि टास्क 1 को अनिश्चित काल तक अवरुद्ध अवस्था में रोका जा सके जब तक कि sema_v उपलब्ध न हो।
अब, आइए इन एपीआई का उपयोग करें और कुछ कार्यों को करने के लिए एक कोड लिखें।
यहां एक पुश-बटन और दो एलईडी इंटरफेयर हैं। पुश-बटन एक इंटरप्ट बटन की तरह काम करेगा जो कि Arduino Uno के पिन 2 से जुड़ा है। जब इस बटन को दबाया जाता है तो एक अवरोध उत्पन्न होगा और एक एलईडी जो पिन 8 से जुड़ी है चालू हो जाएगी और जब आप इसे फिर से दबाएंगे तो यह बंद हो जाएगा।
इसलिए, जब बटन दबाया जाता है xSemaphoreGiveFromISR () ISR फ़ंक्शन से कॉल किया जाएगा और xSemaphoreTake () फ़ंक्शन टास्कएलईडी फ़ंक्शन से कॉल किया जाएगा।
सिस्टम को मल्टीटास्किंग बनाने के लिए, अन्य एल ई डी को पिन 7 से कनेक्ट करें जो हमेशा ब्लिंकिंग स्थिति में होगा।
सेमीफोर कोड स्पष्टीकरण
आइए Arduino IDE खोलकर कोड लिखना शुरू करें
1. सबसे पहले, Arduino_FreeRTOS.h हैडर फ़ाइल शामिल करें । अब, यदि किसी भी कर्नेल ऑब्जेक्ट का उपयोग कतार सेमाफोर की तरह किया जाता है, तो इसके लिए एक हेडर फ़ाइल को भी शामिल किया जाना चाहिए।
# अकेला छोड़ दो
2. सेमाफोर के मानों को संग्रहीत करने के लिए SemaphoreHandle_t के एक प्रकार की घोषणा करें ।
सेमाफोरहैंडल_ट इंटरसेपमेंट;
3. शून्य सेटअप () में, xTaskCreate () API का उपयोग करके दो कार्य (टास्कलैड और टास्कलिंक) बनाएं और फिर xSemaphoreCreateBinary () का उपयोग करके एक सेमाफोर बनाएं और समान प्राथमिकताओं के लिए एक कार्य बनाएं और बाद में इस संख्या के साथ खेलने का प्रयास करें। इसके अलावा, पिन 2 को एक इनपुट के रूप में कॉन्फ़िगर करें और आंतरिक पुल-अप रोकनेवाला को सक्षम करें और इंटरप्ट पिन संलग्न करें। अंत में, शेड्यूलर को नीचे दिखाए अनुसार शुरू करें।
शून्य सेटअप () { pinMode (2, INPUT_PULLUP); xTaskCreate (टास्कलेड, "लेड", 128, NULL, 0, NULL); xTaskCreate (TaskBlink, "LedBlink", 128, NULL, 0, NULL); बीच-बचाव = xSemaphoreCreateBinary (); if (बीच में आने वाली बाधा! = NULL) { संलग्नक (digitalPinToInterrupt (2), debounceInterrupt, LOW); } }
4. अब, ISR फ़ंक्शन को लागू करें। एक फ़ंक्शन बनाएं और इसे संलग्नक के दूसरे तर्क के रूप में नाम दें () फ़ंक्शन। व्यवधान को ठीक से काम करने के लिए, आपको मिलिब या माइक्रोस फ़ंक्शन का उपयोग करके और डिबगिंग समय को समायोजित करके पुशबटन की डेबिट समस्या को दूर करने की आवश्यकता है। इस फ़ंक्शन से, कॉल इंटरहैंडलर () फ़ंक्शन को नीचे दिखाया गया है।
लंबी डिबंसिंग_टाइम = 150; अस्थिर अहस्ताक्षरित लंबे last_micros; void debounceInterrupt () { if ((long) (micros () - last_micros)> = debouncing_time * 1000) {interHandler (); last_micros = micros (); } }
में interruptHandler () समारोह, फोन xSemaphoreGiveFromISR () एपीआई।
शून्य व्यवधानहैंडलर () { xSemaphoreGiveFromISR (व्यवधान, NULL); }
यह फ़ंक्शन टास्कएलड को एलईडी चालू करने के लिए एक सेमाफोर देगा।
5. एक बनाएं TaskLed समारोह और अंदर जबकि पाश, कॉल xSemaphoreTake () एपीआई और देखें कि क्या सेमाफोर सफलतापूर्वक पूरा कर लिया है या नहीं है। अगर यह pdPASS (यानी 1) के बराबर है तो नीचे दिखाए अनुसार एलईडी टॉगल करें।
शून्य टास्कलैड (शून्य * pvParameters) { (शून्य) pvParameters; पिनमोड (8, OUTPUT); जबकि (1) { if (xSemaphoreTake (इंटरसेपमेंट, portMAX_DELAY) == pdPASS) { digitalWrite (8; digitalRead (8)); } } }
6. इसके अलावा, पिन 7 से जुड़े अन्य एलईडी को ब्लिंक करने के लिए एक फ़ंक्शन बनाएं।
शून्य टास्कलैड 1 (शून्य * pvParameters) { (शून्य) pvParameters; पिनमोड (7, OUTPUT); जबकि (1) { digitalWrite (7, उच्च); vTaskDelay (200 / portTICK_PERIOD_MS); digitalWrite (7, LOW); vTaskDelay (200 / portTICK_PERIOD_MS); } }
7. शून्य लूप फ़ंक्शन खाली रहेगा। इसे मत भूलना।
शून्य लूप () {}
यही है, इस ट्यूटोरियल के अंत में पूरा कोड पाया जा सकता है। अब, इस कोड को अपलोड करें और सर्किट डायग्राम के अनुसार एलईडी और पुश-बटन को Arduino UNO से कनेक्ट करें।
सर्किट आरेख
कोड अपलोड करने के बाद, आप देखेंगे कि एक एलईडी 200ms के बाद झपकी ले रही है और जब बटन दबाया जाता है, तो तुरंत दूसरी एलईडी चमक जाएगी जैसा कि अंत में दिए गए वीडियो में दिखाया गया है।
इस तरह, Arduino के साथ FreeRTOS में सेमाफोरस का उपयोग किया जा सकता है, जहां इसे बिना किसी नुकसान के एक कार्य से दूसरे डेटा को पास करना होगा।
अब, देखते हैं कि म्यूटेक्स क्या है और इसे फ्रीआरटीओएस का उपयोग कैसे करें।
म्यूटेक्स क्या है?
जैसा कि सेमाफोर के ऊपर बताया गया है कि एक सिग्नलिंग मैकेनिज्म है, इसी तरह, म्यूटेक्स सेमीफोर के विपरीत एक लॉकिंग मैकेनिज्म है जिसमें इंक्रीमेंट और डीक्रीमेंट के लिए अलग-अलग फंक्शन होते हैं, लेकिन म्यूटेक्स में फंक्शन अपने आप ही हो जाता है। यह साझा संसाधनों के भ्रष्टाचार से बचने की एक तकनीक है।
साझा संसाधन की सुरक्षा के लिए, एक संसाधन को टोकन कार्ड (म्यूटेक्स) प्रदान करता है। जिसके पास यह कार्ड है वह दूसरे संसाधन तक पहुंच सकता है। दूसरों को तब तक इंतजार करना चाहिए जब तक कार्ड वापस नहीं आ जाता। इस तरह, केवल एक संसाधन कार्य तक पहुंच सकता है और अन्य अपने मौके की प्रतीक्षा करते हैं।
आइए एक उदाहरण की मदद से फ्रीटोस में म्यूटेक्स को समझते हैं ।
यहां हमारे पास तीन कार्य हैं, एक एलसीडी पर डेटा प्रिंट करने के लिए, दूसरा एलडीआर डेटा को एलसीडी कार्य पर भेजने के लिए और दूसरा कार्य एलसीडी पर तापमान डेटा भेजने के लिए। इसलिए यहाँ दो कार्य समान संसाधन अर्थात LCD साझा कर रहे हैं। यदि LDR कार्य और तापमान कार्य एक साथ डेटा भेजते हैं तो डेटा में से एक दूषित या खो सकता है।
इसलिए डेटा हानि से बचाने के लिए, हमें टास्क 1 के लिए एलसीडी संसाधन को लॉक करना होगा जब तक कि यह डिस्प्ले टास्क पूरा नहीं कर लेता। फिर LCD टास्क अनलॉक होगा और फिर task2 अपना काम कर सकता है।
आप नीचे दिए गए आरेख में म्यूटेक्स और सेमाफोरस के कामकाज का निरीक्षण कर सकते हैं।
FreeRTOS में म्यूटेक्स का उपयोग कैसे करें?
म्यूटेक्स का उपयोग उसी तरह से किया जाता है जैसे कि सेमीफोर में। सबसे पहले, इसे बनाएं, फिर संबंधित एपीआई का उपयोग करके दें।
एक म्यूटेक्स बनाना:
Mutex बनाने के लिए, xSemaphoreCreateMutex () API का उपयोग करें । जैसा कि इसके नाम से पता चलता है कि म्यूटेक्स एक प्रकार का बाइनरी सेमाफोर है। उनका उपयोग विभिन्न संदर्भों और उद्देश्यों में किया जाता है। एक बाइनरी सेमाफोर कार्यों को सिंक्रनाइज़ करने के लिए है जबकि म्यूटेक्स का उपयोग एक साझा संसाधन की सुरक्षा के लिए किया जाता है।
यह API कोई तर्क नहीं देता है और SemaphoreHandle_t प्रकार का एक चर लौटाता है । यदि म्यूटेक्स नहीं बनाया जा सकता है, तो xSemaphoreCreateMutex () NULL लौटें।
सेमफोरहैंडल_ट म्यूटेक्स_व; mutex_v = xSemaphoreCreateMutex ();
एक म्यूटेक्स लेना:
जब कोई कार्य किसी संसाधन तक पहुँचना चाहता है, तो यह xSemaphoreTake () API का उपयोग करके एक Mutex लेगा । यह बाइनरी सेमाफोर के समान है। यह दो पैरामीटर भी लेता है।
xSemaphore: हमारे मामले में लिया जाने वाला म्यूटेक्स का नाम mutex_v ।
xTicksToWait: यह अधिकतम समय है कि कार्य म्यूटेक्स के उपलब्ध होने के लिए अवरुद्ध अवस्था में प्रतीक्षा करेगा। हमारी परियोजना में, हम mutex_v के उपलब्ध होने तक अवरुद्ध अवस्था में अनिश्चित काल तक प्रतीक्षा करने के लिए task_1 बनाने के लिए portMAX_DELAY को xTicksToWait सेट करेंगे ।
एक म्यूटेक्स देते हुए:
साझा संसाधन तक पहुंचने के बाद, कार्य को म्यूटेक्स को वापस करना चाहिए ताकि अन्य कार्य इसे एक्सेस कर सकें। XSemaphoreGive () एपीआई का उपयोग म्यूटेक्स को वापस देने के लिए किया जाता है।
XSemaphoreGive () फ़ंक्शन केवल एक तर्क लेता है जो हमारे मामले में दिया जाने वाला Mutex है mutex_v।
उपरोक्त एपीआई का उपयोग करते हुए, आइए Arduino IDE का उपयोग करके फ्रीट्रॉस कोड में म्यूटेक्स को लागू करें ।
म्यूटेक्स कोड स्पष्टीकरण
यहां इस भाग के लिए लक्ष्य एक साझा संसाधन के रूप में सीरियल मॉनिटर का उपयोग करना है और कुछ संदेश को प्रिंट करने के लिए सीरियल मॉनिटर तक पहुंचने के लिए दो अलग-अलग कार्य हैं।
1. हेडर फाइलें सेमफोर की तरह ही रहेंगी।
# अकेला छोड़ दो
2. Mutex के मूल्यों को संग्रहीत करने के लिए SemaphoreHandle_t प्रकार का एक वैरिएबल घोषित करें ।
सेमफोरहैंडल_ट म्यूटेक्स_व;
3. शून्य सेटअप () में, 9600 बॉड रेट के साथ सीरियल मॉनिटर को इनिशियलाइज़ करें और xTaskCreate () एपीआई का उपयोग करके दो कार्य (टास्क 1 और टास्क 2) बनाएं । फिर xSemaphoreCreateMutex () का उपयोग करके एक म्यूटेक्स बनाएं । समान प्राथमिकताओं के साथ एक कार्य बनाएं और बाद में इस संख्या के साथ खेलने का प्रयास करें।
शून्य सेटअप () { Serial.begin (9600); mutex_v = xSemaphoreCreateMutex (); if (mutex_v == NULL) {Serial.println ("Mutex नहीं बनाया जा सकता"); } xTaskCreate (टास्क 1, "टास्क 1", 128, NULL, 1, NULL); xTaskCreate (टास्क 2, "टास्क 2", 128, NULL, 1, NULL); }
4. अब, टास्क 1 और टास्क 2 के लिए कार्य करें। कार्य फ़ंक्शन के कुछ समय के लूप में, सीरियल मॉनीटर पर संदेश प्रिंट करने से पहले हमें xSemaphoreTake () का उपयोग करके एक म्यूटेक्स लेना होगा और फिर संदेश को प्रिंट करना होगा और फिर xSemaphoreGive () का उपयोग करके म्यूटेक्स को वापस करना होगा । फिर कुछ देर दे।
शून्य टास्क 1 (शून्य * pvParameters) { जबकि (1) { xSemaphoreTake (mutex_v, portMAX_DELAY); Serial.println ("टास्क 1 से हाय"); xSemaphoreGive (mutex_v); vTaskDelay (pdMS_TO_TICKS (1000)); } }
इसी तरह, 500ms की देरी के साथ टास्क 2 फ़ंक्शन को लागू करें।
5. शून्य लूप () खाली रहेगा।
अब, इस कोड को Arduino UNO पर अपलोड करें और सीरियल मॉनिटर खोलें।
आप देखेंगे कि टास्क 1 और टास्क 2 से संदेश प्रिंट हो रहे हैं।
म्यूटेक्स के कामकाज का परीक्षण करने के लिए, बस xSemaphoreGive (mutex_v) पर टिप्पणी करें ; किसी कार्य से। आप देख सकते हैं कि प्रोग्राम अंतिम प्रिंट संदेश पर लटका हुआ है ।
इस तरह से Arduino के साथ FreeRTOS में सेमाफोर और म्यूटेक्स को लागू किया जा सकता है। सेमाफोर और म्यूटेक्स के बारे में अधिक जानकारी के लिए, आप फ्रीआरटीओएस के आधिकारिक दस्तावेज देख सकते हैं।
सेमफोर और म्यूट्स के लिए पूर्ण कोड और वीडियो नीचे दिए गए हैं।