थ्रेडेड कोड: Difference between revisions

From Vigyanwiki
(Created page with "{{Short description|Program whose source code consists entirely of calls to functions}} {{confuse|Multi-threaded programming|Jump threading}} कंप्यूटर वि...")
 
No edit summary
Line 1: Line 1:
{{Short description|Program whose source code consists entirely of calls to functions}}
{{Short description|Program whose source code consists entirely of calls to functions}}
{{confuse|Multi-threaded programming|Jump threading}}
''मल्टी-थ्रेडेड प्रोग्रामिंग या जंप थ्रेडिंग से भ्रमित न हों।''
[[कंप्यूटर विज्ञान]] में, थ्रेडेड कोड एक प्रोग्रामिंग तकनीक है जहां स्रोत कोड का एक रूप होता है जो अनिवार्य रूप से पूरी तरह से [[सबरूटीन]]्स को कॉल करता है। यह अक्सर [[संकलक]]्स में प्रयोग किया जाता है, जो उस रूप में कोड उत्पन्न कर सकता है या स्वयं उस रूप में कार्यान्वित किया जा सकता है। कोड को [[दुभाषिया (कंप्यूटिंग)]] द्वारा संसाधित किया जा सकता है या यह केवल [[मशीन कोड]] कॉल निर्देशों का अनुक्रम हो सकता है।


थ्रेडेड कोड में वैकल्पिक पीढ़ी तकनीकों और वैकल्पिक कॉलिंग सम्मेलनों द्वारा उत्पन्न कोड की तुलना में बेहतर [[कोड घनत्व]] होता है। [[कैश (कंप्यूटिंग)]] आर्किटेक्चर में, यह [[निष्पादन (कंप्यूटिंग)]] थोड़ा धीमा हो सकता है।{{citation needed|date=February 2012}} हालाँकि, एक प्रोग्राम जो एक [[कंप्यूटर प्रोसेसर]] के CPU कैश में फिट होने के लिए काफी छोटा है, एक बड़े प्रोग्राम की तुलना में तेजी से चल सकता है जो कई [[कैश मिस]] से ग्रस्त है।<ref name="tuwien1">{{cite web|url=http://www.complang.tuwien.ac.at/forth/threading/ |title=Speed of various interpreter dispatch techniques V2}}</ref> [[धागा स्विच]]िंग पर छोटे प्रोग्राम भी तेज़ हो सकते हैं, जब अन्य प्रोग्राम कैश भर चुके हों।
[[कंप्यूटर विज्ञान]] में, थ्रेडेड कोड एक प्रोग्रामिंग तकनीक है जहां स्रोत कोड का एक रूप होता है जो अनिवार्य रूप से पूरी तरह से [[सबरूटीन]]्स को कॉल करता है। यह प्रायः [[संकलक]]्स में प्रयोग किया जाता है, जो उस रूप में कोड उत्पन्न कर सकता है या स्वयं उस रूप में कार्यान्वित किया जा सकता है। कोड को [[दुभाषिया (कंप्यूटिंग)]] द्वारा संसाधित किया जा सकता है या यह केवल [[मशीन कोड]] कॉल निर्देशों का अनुक्रम हो सकता है।
 
थ्रेडेड कोड में वैकल्पिक पीढ़ी तकनीकों और वैकल्पिक कॉलिंग सम्मेलनों द्वारा उत्पन्न कोड की तुलना में बेहतर [[कोड घनत्व]] होता है। [[कैश (कंप्यूटिंग)]] आर्किटेक्चर में, यह [[निष्पादन (कंप्यूटिंग)]] थोड़ा धीमा हो सकता है।{{citation needed|date=February 2012}} हालाँकि, एक प्रोग्राम जो एक [[कंप्यूटर प्रोसेसर]] के सेंट्रल प्रोसेसिंग यूनिट कैश में फिट होने के लिए काफी छोटा है, एक बड़े प्रोग्राम की तुलना में तेजी से चल सकता है जो कई [[कैश मिस]] से ग्रस्त है।<ref name="tuwien1">{{cite web|url=http://www.complang.tuwien.ac.at/forth/threading/ |title=Speed of various interpreter dispatch techniques V2}}</ref> [[धागा स्विच]]िंग पर छोटे प्रोग्राम भी तेज़ हो सकते हैं, जब अन्य प्रोग्राम कैश भर चुके हों।
 
थ्रेडेड कोड को [[प्रोग्रामिंग भाषा]] के कई कंपाइलरों में इसके उपयोग के लिए जाना जाता है, जैसे [[फोर्थ (प्रोग्रामिंग भाषा)]], [[बुनियादी]] के कई कार्यान्वयन, [[COBOL|सामान्य व्यवसाय उन्मुखी भाषा]] के कुछ कार्यान्वयन, B के प्रारम्भिक संस्करण (प्रोग्रामिंग लैंग्वेज),<ref>Dennis M. Ritchie, [https://www.bell-labs.com/usr/dmr/www/chist.html "The Development of the C Language"], 1993. Quote: "The B compiler on the PDP-7 did not generate machine instructions, but instead 'threaded code' ..."</ref> और छोटे [[मिनी कंप्यूटर]] और [[शौकिया रेडियो उपग्रह]]ों के लिए अन्य भाषाएं।{{citation needed|date=February 2016}}


थ्रेडेड कोड को [[प्रोग्रामिंग भाषा]] के कई कंपाइलरों में इसके उपयोग के लिए जाना जाता है, जैसे [[फोर्थ (प्रोग्रामिंग भाषा)]], [[बुनियादी]] के कई कार्यान्वयन, [[COBOL]] के कुछ कार्यान्वयन, B के शुरुआती संस्करण (प्रोग्रामिंग लैंग्वेज),<ref>Dennis M. Ritchie, [https://www.bell-labs.com/usr/dmr/www/chist.html "The Development of the C Language"], 1993. Quote: "The B compiler on the PDP-7 did not generate machine instructions, but instead 'threaded code' ..."</ref> और छोटे [[मिनी कंप्यूटर]] और [[शौकिया रेडियो उपग्रह]]ों के लिए अन्य भाषाएं।{{citation needed|date=February 2016}}




== इतिहास ==
== इतिहास ==
{{Original research section|date=February 2020}}
{{Original research section|date=February 2020}}
कंप्यूटर प्रोग्राम बनाने का सामान्य तरीका मशीन कोड में स्रोत कोड (कुछ [[प्रतीकात्मक भाषा (प्रोग्रामिंग)]] में लिखा गया) का अनुवाद करने के लिए एक कंपाइलर का उपयोग करना है। परिणामी [[निष्पादन]] योग्य आमतौर पर तेज़ होता है लेकिन, क्योंकि यह [[कंप्यूटर हार्डवेयर]] प्लेटफ़ॉर्म के लिए विशिष्ट है, यह पोर्टेबल नहीं है। एक [[आभासी मशीन]] के लिए निर्देश सेट उत्पन्न करने और प्रत्येक हार्डवेयर प्लेटफॉर्म पर दुभाषिया (कंप्यूटिंग) का उपयोग करने के लिए एक अलग दृष्टिकोण है। दुभाषिया वर्चुअल मशीन वातावरण को तुरंत चालू करता है और निर्देशों को निष्पादित करता है। इस प्रकार, केवल दुभाषिया को संकलित किया जाना चाहिए।
कंप्यूटर प्रोग्राम बनाने का सामान्य तरीका मशीन कोड में स्रोत कोड (कुछ [[प्रतीकात्मक भाषा (प्रोग्रामिंग)]] में लिखा गया) का अनुवाद करने के लिए एक कंपाइलर का उपयोग करना है। परिणामी [[निष्पादन]] योग्य सामान्य रूप से तेज़ होता है लेकिन, क्योंकि यह [[कंप्यूटर हार्डवेयर]] प्लेटफ़ॉर्म के लिए विशिष्ट है, यह पोर्टेबल नहीं है। एक [[आभासी मशीन]] के लिए निर्देश सेट उत्पन्न करने और प्रत्येक हार्डवेयर प्लेटफॉर्म पर दुभाषिया (कंप्यूटिंग) का उपयोग करने के लिए एक अलग दृष्टिकोण है। दुभाषिया वर्चुअल मशीन वातावरण को तुरंत चालू करता है और निर्देशों को निष्पादित करता है। इस प्रकार, केवल दुभाषिया को संकलित किया जाना चाहिए।


शुरुआती कंप्यूटरों में अपेक्षाकृत कम मेमोरी होती थी। उदाहरण के लिए, अधिकांश [[दिनांक जनरल नोवा]], [[IBM 1130]], और कई पहले [[माइक्रो]] कंप्यूटरों में केवल 4 kB RAM स्थापित थी। नतीजतन, उपलब्ध मेमोरी में फिट होने के लिए प्रोग्राम के आकार को कम करने के तरीके खोजने की कोशिश में बहुत समय व्यतीत हुआ।
प्रारम्भिक कंप्यूटरों में अपेक्षाकृत कम मेमोरी होती थी। उदाहरण के लिए, अधिकांश [[दिनांक जनरल नोवा]], [[IBM 1130]], और कई पहले [[माइक्रो]] कंप्यूटरों में केवल 4 kB RAM स्थापित थी। नतीजतन, उपलब्ध मेमोरी में फिट होने के लिए प्रोग्राम के आकार को कम करने के तरीके खोजने की कोशिश में बहुत समय व्यतीत हुआ।


एक समाधान एक दुभाषिया का उपयोग करना है जो एक समय में प्रतीकात्मक भाषा को थोड़ा पढ़ता है, और कार्यों को करने के लिए कार्यों को बुलाता है। चूंकि स्रोत कोड आमतौर पर परिणामी मशीन कोड की तुलना में अधिक कोड घनत्व होता है, यह समग्र मेमोरी उपयोग को कम कर सकता है। यही कारण था कि [[Microsoft BASIC]] एक दुभाषिया है:{{efn|[[Dartmouth BASIC]], upon which [[Microsoft BASIC]] is ultimately based, was a compiler that ran on mainframe machines.}} इसके अपने कोड को [[Altair 8800]] जैसी मशीनों की 4 kB मेमोरी को उपयोगकर्ता के स्रोत कोड के साथ साझा करना था। एक कंपाइलर सोर्स लैंग्वेज से मशीन कोड में ट्रांसलेट होता है, इसलिए कंपाइलर, सोर्स और आउटपुट सभी एक ही समय में मेमोरी में होने चाहिए। एक दुभाषिया में, कोई आउटपुट नहीं होता है।
एक समाधान एक दुभाषिया का उपयोग करना है जो एक समय में प्रतीकात्मक भाषा को थोड़ा पढ़ता है, और कार्यों को करने के लिए कार्यों को बुलाता है। चूंकि स्रोत कोड सामान्य रूप से परिणामी मशीन कोड की तुलना में अधिक कोड घनत्व होता है, यह समग्र मेमोरी उपयोग को कम कर सकता है। यही कारण था कि [[Microsoft BASIC|Microsoft सामान्य संयुक्त प्रोग्रामिंग भाषा]] एक दुभाषिया है:{{efn|[[Dartmouth BASIC]], upon which [[Microsoft BASIC]] is ultimately based, was a compiler that ran on mainframe machines.}} इसके अपने कोड को [[Altair 8800]] जैसी मशीनों की 4 kB मेमोरी को उपयोगकर्ता के स्रोत कोड के साथ साझा करना था। एक कंपाइलर सोर्स लैंग्वेज से मशीन कोड में ट्रांसलेट होता है, इसलिए कंपाइलर, सोर्स और आउटपुट सभी एक ही समय में मेमोरी में होने चाहिए। एक दुभाषिया में, कोई आउटपुट नहीं होता है।


थ्रेडेड कोड संकलित कोड के लिए एक स्वरूपण शैली है जो स्मृति उपयोग को कम करता है। कार्यक्रम में प्रत्येक घटना पर एक ऑपरेशन के हर चरण को लिखने के बजाय, जैसा कि उदाहरण के लिए [[मैक्रो कोडांतरक]] में आम था, संकलक कोड के प्रत्येक सामान्य बिट को सबरूटीन में लिखता है। इस प्रकार, प्रत्येक बिट स्मृति में केवल एक ही स्थान पर मौजूद है (देखें स्वयं को दोहराएं नहीं)। इन कार्यक्रमों में शीर्ष-स्तरीय एप्लिकेशन में सबरूटीन कॉल के अलावा और कुछ नहीं हो सकता है। इन सबरूटीन्स में से कई, बदले में, निचले स्तर के सबरूटीन कॉल्स के अलावा और कुछ नहीं होते हैं।
थ्रेडेड कोड संकलित कोड के लिए एक स्वरूपण शैली है जो स्मृति उपयोग को कम करता है। कार्यक्रम में प्रत्येक घटना पर एक ऑपरेशन के हर चरण को लिखने के बजाय, जैसा कि उदाहरण के लिए [[मैक्रो कोडांतरक]] में आम था, संकलक कोड के प्रत्येक सामान्य बिट को सबरूटीन में लिखता है। इस प्रकार, प्रत्येक बिट स्मृति में केवल एक ही स्थान पर सम्मिलित है (देखें स्वयं को दोहराएं नहीं)। इन कार्यक्रमों में शीर्ष-स्तरीय एप्लिकेशन में सबरूटीन कॉल के अलावा और कुछ नहीं हो सकता है। इन सबरूटीन्स में से कई, बदले में, निचले स्तर के सबरूटीन कॉल्स के अलावा और कुछ नहीं होते हैं।


मेनफ्रेम और कुछ शुरुआती माइक्रोप्रोसेसरों जैसे [[आरसीए 1802]] को सबरूटीन कॉल करने के लिए कई निर्देशों की आवश्यकता होती है। शीर्ष-स्तरीय एप्लिकेशन में और कई सबरूटीन्स में, उस क्रम को लगातार दोहराया जाता है, जिसमें केवल सबरूटीन एड्रेस एक कॉल से दूसरे कॉल में बदलता रहता है। इसका मतलब यह है कि कई फ़ंक्शन कॉल वाले प्रोग्राम में काफी मात्रा में बार-बार कोड भी हो सकता है।
मेनफ्रेम और कुछ प्रारम्भिक माइक्रोप्रोसेसरों जैसे [[आरसीए 1802]] को सबरूटीन कॉल करने के लिए कई निर्देशों की आवश्यकता होती है। शीर्ष-स्तरीय एप्लिकेशन में और कई सबरूटीन्स में, उस क्रम को लगातार दोहराया जाता है, जिसमें केवल सबरूटीन एड्रेस एक कॉल से दूसरे कॉल में बदलता रहता है। इसका मतलब यह है कि कई फ़ंक्शन कॉल वाले प्रोग्राम में काफी मात्रा में बार-बार कोड भी हो सकता है।


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


1970 के दशक के दौरान, हार्डवेयर डिजाइनरों ने सबरूटीन कॉल को तेज और सरल बनाने के लिए काफी प्रयास किया। बेहतर डिजाइनों पर, सबरूटीन को कॉल करने के लिए केवल एक ही निर्देश खर्च किया जाता है, इसलिए छद्म निर्देश का उपयोग कोई जगह नहीं बचाता है।{{Citation needed|date=March 2020|reason=storing only the address of the subroutine actually does save room compared to storing a call instruction, which necessarily must contain something in addition to the address of the subroutine.}} इसके अतिरिक्त, इन कॉलों का प्रदर्शन अतिरिक्त ओवरहेड से लगभग मुक्त है। आज, हालांकि लगभग सभी प्रोग्रामिंग भाषाएं सबरूटीन्स में कोड को अलग करने पर ध्यान केंद्रित करती हैं, वे ऐसा कोड स्पष्टता और रखरखाव के लिए करते हैं, स्थान बचाने के लिए नहीं।
1970 के दशक के समय, हार्डवेयर डिजाइनरों ने सबरूटीन कॉल को तेज और सरल बनाने के लिए काफी प्रयास किया। बेहतर डिजाइनों पर, सबरूटीन को कॉल करने के लिए केवल एक ही निर्देश खर्च किया जाता है, इसलिए छद्म निर्देश का उपयोग कोई जगह नहीं बचाता है।{{Citation needed|date=March 2020|reason=storing only the address of the subroutine actually does save room compared to storing a call instruction, which necessarily must contain something in addition to the address of the subroutine.}} इसके अतिरिक्त, इन कॉलों का प्रदर्शन अतिरिक्त ओवरहेड से लगभग मुक्त है। आज, हालांकि लगभग सभी प्रोग्रामिंग भाषाएं सबरूटीन्स में कोड को अलग करने पर ध्यान केंद्रित करती हैं, वे ऐसा कोड स्पष्टता और रखरखाव के लिए करते हैं, स्थान बचाने के लिए नहीं।


थ्रेडेड कोड सिस्टम फ़ंक्शन कॉल की उस सूची को बदलकर कमरे को बचाते हैं, जहां निष्पादन टोकन की सूची के साथ केवल सबरूटीन पता एक कॉल से दूसरे कॉल में बदलता है, जो अनिवार्य रूप से कॉल ऑपकोड (ओं) के साथ फ़ंक्शन कॉल होते हैं, पीछे छोड़ देते हैं केवल पतों की एक सूची।<ref>
थ्रेडेड कोड सिस्टम फ़ंक्शन कॉल की उस सूची को बदलकर कमरे को बचाते हैं, जहां निष्पादन टोकन की सूची के साथ केवल सबरूटीन पता एक कॉल से दूसरे कॉल में बदलता है, जो अनिवार्य रूप से कॉल ऑपकोड (ओं) के साथ फ़ंक्शन कॉल होते हैं, पीछे छोड़ देते हैं केवल पतों की एक सूची।<ref>
Line 47: Line 49:
p. 212
p. 212
</ref>
</ref>
इन वर्षों में, प्रोग्रामर ने उस दुभाषिया या छोटे चयनकर्ता पर कई बदलाव किए हैं। पतों की सूची में विशेष पता एक इंडेक्स, [[सामान्य प्रयोजन रजिस्टर]] या [[सूचक (कंप्यूटर प्रोग्रामिंग)]] का उपयोग करके निकाला जा सकता है। पते प्रत्यक्ष या अप्रत्यक्ष, सन्निहित या गैर-सन्निहित (पॉइंटर्स द्वारा जुड़े हुए), सापेक्ष या निरपेक्ष, संकलन समय पर हल या गतिशील रूप से निर्मित हो सकते हैं। सभी परिस्थितियों के लिए कोई भी भिन्नता सर्वोत्तम नहीं है।
इन वर्षों में, प्रोग्रामर ने उस दुभाषिया या छोटे चयनकर्ता पर कई बदलाव किए हैं। पतों की सूची में विशेष पता एक इंडेक्स, [[सामान्य प्रयोजन रजिस्टर]] या [[सूचक (कंप्यूटर प्रोग्रामिंग)]] का उपयोग करके निकाला जा सकता है। एड्रैस प्रत्यक्ष या अप्रत्यक्ष, सन्निहित या गैर-सन्निहित (पॉइंटर्स द्वारा जुड़े हुए), सापेक्ष या निरपेक्ष, संकलन समय पर हल या गतिशील रूप से निर्मित हो सकते हैं। सभी परिस्थितियों के लिए कोई भी भिन्नता सर्वोत्तम नहीं है।


== विकास ==
== विकास ==
जगह बचाने के लिए, प्रोग्रामर्स ने सबरूटीन कॉल्स की सूचियों को सबरूटीन पतों की सरल सूचियों में निचोड़ा, और बदले में प्रत्येक सबरूटीन को कॉल करने के लिए एक छोटे लूप का उपयोग किया। उदाहरण के लिए, निम्नलिखित स्यूडोकोड दो संख्याओं A और B को जोड़ने के लिए इस तकनीक का उपयोग करता है। उदाहरण में, सूची को थ्रेड लेबल किया गया है और एक चर ip (निर्देश सूचक) सूची के भीतर हमारे स्थान को ट्रैक करता है। एक अन्य चर एसपी (स्टैक पॉइंटर) में मेमोरी में कहीं और पता होता है जो अस्थायी रूप से मान रखने के लिए उपलब्ध होता है।
जगह बचाने के लिए, प्रोग्रामर्स ने सबरूटीन कॉल्स की सूचियों को सबरूटीन पतों की सरल सूचियों में निचोड़ा, और बदले में प्रत्येक सबरूटीन को कॉल करने के लिए एक छोटे लूप का उपयोग किया। उदाहरण के लिए, निम्नलिखित स्यूडोकोड दो संख्याओं A और B को जोड़ने के लिए इस तकनीक का उपयोग करता है। उदाहरण में, सूची को थ्रेड लेबल किया गया है और एक चर ip (निर्देश सूचक) सूची के भीतर हमारे स्थान को ट्रैक करता है। एक अन्य चर एसपी (स्टैक पॉइंटर) में मेमोरी में कहीं और पता होता है जो अस्थायी रूप से मान रखने के लिए उपलब्ध होता है।
 
start:
<वाक्यविन्यास प्रकाश लैंग = सी>
  ip = &thread // points to the address '&pushA', not the textual label 'thread'
शुरू करना:
top:
  ip = &thread // '&pushA' पते की ओर इशारा करता है, पाठ्य लेबल 'धागा' नहीं
  jump *ip++ // follow ip to address in thread, follow that address to subroutine, advance ip
ऊपर:
thread:
  जंप *आईपी++ // थ्रेड में पता करने के लिए आईपी का पालन करें, सबरूटीन के लिए उस पते का पालन करें, अग्रिम आईपी
  &pushA
धागा:
  &pushB
  &pushA
  &add
  &pushB
  ...
  &जोड़ना
pushA:
  ...
  *sp++ = A // follow sp to available memory, store A there, advance sp to next
पुशा:
  jump top
  *sp++ = A // उपलब्ध मेमोरी के लिए sp का अनुसरण करें, वहां A को स्टोर करें, आगे sp को आगे बढ़ाएं
pushB:
  ऊपर कूदो
  *sp++ = B
पुशबी:
  jump top
  *एसपी++ = बी
add:
  ऊपर कूदो
  addend1 = *--sp // Pop the top value off the stack
जोड़ना:
  addend2 = *--sp // Pop second value off the stack
  addend1 = *--sp // स्टैक से शीर्ष मान पॉप करें
  *sp++ = addend1 + addend2 // Add the two values together and store the result on the top of the stack
  addend2 = *--sp // स्टैक से दूसरा मान पॉप करें
  jump top
  *sp++ = addend1 + addend2 // दोनों मानों को एक साथ जोड़ें और परिणाम को स्टैक के शीर्ष पर संग्रहीत करें
कॉलिंग लूप at <code>top</code> इतना सरल है कि इसे प्रत्येक उपनेमका के अंत में इनलाइन दोहराया जा सकता है। नियंत्रण अब एक बार कूदता है, एक उपनेमका के अंत से दूसरे की प्रारंभ तक, दो बार कूदने के बजाय <code>top</code>. उदाहरण के लिए:
  ऊपर कूदो
start:
</वाक्यविन्यास हाइलाइट>
  ip = &thread // ip points to &pushA (which points to the first instruction of pushA)
 
  jump *ip++ // send control to first instruction of pushA and advance ip to &pushB
<!--In this case, decoding the [[bytecode]]s is performed once, during program compilation or program load, so it is not repeated each time an instruction is executed. This can save much time and space when decode and dispatch overhead is large compared to the execution cost.
thread:
 
  &pushA
Note, however, addresses in <code>thread</code> for <code>&pushA</code>, <code>&pushB</code>, etc., are two or more bytes, compared to (typically) one byte, for the decode and dispatch interpreter described above. In general, instructions for a decode and dispatch interpreter may be any size. For example, a decode and dispatch interpreter to simulate an Intel Pentium decodes instructions that range from 1 to 16 bytes. However, bytecoded systems typically choose 1-byte codes for the most-common operations. Thus, the thread often has a higher space cost than bytecodes. In most uses, the reduction in decode cost outweighs the increase in space cost.
  &pushB
 
  &add
Note also that while bytecodes are nominally machine-independent, the format and value of the pointers in threads generally depend on the target machine which is executing the interpreter. Thus, an interpreter might load a portable bytecode program, decode the bytecodes to generate platform-dependent threaded code, then execute threaded code without further reference to the bytecodes.-->
  ...
कॉलिंग लूप at <code>top</code> इतना सरल है कि इसे प्रत्येक उपनेमका के अंत में इनलाइन दोहराया जा सकता है। नियंत्रण अब एक बार कूदता है, एक उपनेमका के अंत से दूसरे की शुरुआत तक, दो बार कूदने के बजाय <code>top</code>. उदाहरण के लिए:
pushA:
 
  *sp++ = A // follow sp to available memory, store A there, advance sp to next
<वाक्यविन्यास प्रकाश लैंग = सी>
  jump *ip++ // send control where ip says to (i.e. to pushB) and advance ip
शुरू करना:
pushB:
  ip = &thread // ip &pushA को इंगित करता है (जो pushA के पहले निर्देश को इंगित करता है)
  *sp++ = B
  jump *ip++ // pushA के पहले निर्देश पर नियंत्रण भेजें और ip को &pushB पर आगे बढ़ाएं
  jump *ip++
धागा:
add:
  &pushA
  addend1 = *--sp // Pop the top value off the stack
  &pushB
  addend2 = *--sp // Pop second value off the stack
  &जोड़ना
  *sp++ = addend1 + addend2 // Add the two values together and store the result on top of the stack
  ...
  jump *ip++
पुशा:
  *sp++ = A // उपलब्ध मेमोरी के लिए sp का अनुसरण करें, वहां A को स्टोर करें, आगे sp को आगे बढ़ाएं
  कूद * आईपी ++ // नियंत्रण भेजें जहां आईपी कहता है (यानी पुशबी के लिए) और अग्रिम आईपी
पुशबी:
  *एसपी++ = बी
  कूदो * आईपी ++
जोड़ना:
  addend1 = *--sp // स्टैक से शीर्ष मान पॉप करें
  addend2 = *--sp // स्टैक से दूसरा मान पॉप करें
  *sp++ = addend1 + addend2 // दोनों मानों को एक साथ जोड़ें और परिणाम को स्टैक के शीर्ष पर संग्रहीत करें
  कूदो * आईपी ++
</वाक्यविन्यास हाइलाइट>
 
इसे डायरेक्ट थ्रेडेड कोड (डीटीसी) कहा जाता है। हालांकि तकनीक पुरानी है, थ्रेडेड कोड शब्द का पहला व्यापक रूप से परिचालित उपयोग संभवतः जेम्स आर. बेल का 1973 का लेख थ्रेडेड कोड है।<ref>{{cite journal|last=Bell|first=James R.|title=Threaded code|journal=Communications of the ACM|year=1973|volume=16|issue=6|pages=370–372|doi=10.1145/362248.362270}}</ref>
इसे डायरेक्ट थ्रेडेड कोड (डीटीसी) कहा जाता है। हालांकि तकनीक पुरानी है, थ्रेडेड कोड शब्द का पहला व्यापक रूप से परिचालित उपयोग संभवतः जेम्स आर. बेल का 1973 का लेख थ्रेडेड कोड है।<ref>{{cite journal|last=Bell|first=James R.|title=Threaded code|journal=Communications of the ACM|year=1973|volume=16|issue=6|pages=370–372|doi=10.1145/362248.362270}}</ref>
1970 में, चार्ल्स एच. मूर ने अपनी फोर्थ वर्चुअल मशीन के लिए एक अधिक कॉम्पैक्ट व्यवस्था, अप्रत्यक्ष थ्रेडेड कोड (ITC) का आविष्कार किया। मूर इस व्यवस्था पर इसलिए पहुंचे क्योंकि डेटा जनरल नोवा मिनीकंप्यूटर के प्रत्येक पते में एक [[अप्रत्यक्ष बिट]] था, जिसने आईटीसी को आसान और तेज़ बना दिया। बाद में, उन्होंने कहा कि उन्हें यह इतना सुविधाजनक लगा कि उन्होंने बाद के सभी फोर्थ डिजाइनों में इसका प्रचार किया।<ref>Moore, Charles H., published remarks in Byte Magazine's Forth Issue</ref>
1970 में, चार्ल्स एच. मूर ने अपनी फोर्थ वर्चुअल मशीन के लिए एक अधिक कॉम्पैक्ट व्यवस्था, अप्रत्यक्ष थ्रेडेड कोड (ITC) का आविष्कार किया। मूर इस व्यवस्था पर इसलिए पहुंचे क्योंकि डेटा जनरल नोवा मिनीकंप्यूटर के प्रत्येक एड्रैस में एक [[अप्रत्यक्ष बिट]] था, जिसने आईटीसी को आसान और तेज़ बना दिया। बाद में, उन्होंने कहा कि उन्हें यह इतना सुविधाजनक लगा कि उन्होंने बाद के सभी फोर्थ डिजाइनों में इसका प्रचार किया।<ref>Moore, Charles H., published remarks in Byte Magazine's Forth Issue</ref>
आज, कुछ फोर्थ कंपाइलर्स प्रत्यक्ष-थ्रेडेड कोड उत्पन्न करते हैं जबकि अन्य अप्रत्यक्ष-थ्रेडेड कोड उत्पन्न करते हैं। निष्पादक किसी भी तरह से कार्य करते हैं।
आज, कुछ फोर्थ कंपाइलर्स प्रत्यक्ष-थ्रेडेड कोड उत्पन्न करते हैं जबकि अन्य अप्रत्यक्ष-थ्रेडेड कोड उत्पन्न करते हैं। निष्पादक किसी भी तरह से कार्य करते हैं।


Line 112: Line 101:


=== डायरेक्ट थ्रेडिंग ===
=== डायरेक्ट थ्रेडिंग ===
थ्रेड में पते मशीनी भाषा के पते होते हैं। यह फॉर्म सरल है, लेकिन इसमें ओवरहेड्स हो सकते हैं क्योंकि थ्रेड में केवल मशीन के पते होते हैं, इसलिए आगे के सभी मापदंडों को अप्रत्यक्ष रूप से मेमोरी से लोड किया जाना चाहिए। कुछ फोर्थ सिस्टम डायरेक्ट-थ्रेडेड कोड उत्पन्न करते हैं। कई मशीनों पर डायरेक्ट-थ्रेडिंग सबरूटीन थ्रेडिंग की तुलना में तेज़ होती है (नीचे संदर्भ देखें)।
थ्रेड में एड्रैस मशीनी भाषा के एड्रैस होते हैं। यह फॉर्म सरल है, लेकिन इसमें ओवरहेड्स हो सकते हैं क्योंकि थ्रेड में केवल मशीन के एड्रैस होते हैं, इसलिए आगे के सभी मापदंडों को अप्रत्यक्ष रूप से मेमोरी से लोड किया जाना चाहिए। कुछ फोर्थ सिस्टम डायरेक्ट-थ्रेडेड कोड उत्पन्न करते हैं। कई मशीनों पर डायरेक्ट-थ्रेडिंग सबरूटीन थ्रेडिंग की तुलना में तेज़ होती है (नीचे संदर्भ देखें)।
 
[[स्टैक मशीन]] का एक उदाहरण अनुक्रम पुश ए, पुश बी, एड को निष्पादित कर सकता है। इसका अनुवाद निम्नलिखित थ्रेड और रूटीन में किया जा सकता है, जहाँ <code>ip</code> लेबल किए गए पते पर प्रारंभ किया गया है <code>thread</code> (यानी, पता जहां <code>&pushA</code> रखा है)।
 
<वाक्यविन्यास प्रकाश लैंग = सी>
#define पुश(x) (*sp++ = (x))
#define POP() (*--sp)
शुरू करना:
  ip = &thread // ip &pushA को इंगित करता है (जो pushA के पहले निर्देश को इंगित करता है)
  jump *ip++ // pushA के पहले निर्देश पर नियंत्रण भेजें और ip को &pushB पर आगे बढ़ाएं
धागा:
  &pushA
  &pushB
  &जोड़ना
  ...
पुशा:
  पुश (ए)
  कूद * आईपी ++ // नियंत्रण भेजें जहां आईपी कहता है (यानी पुशबी के लिए) और अग्रिम आईपी
पुशबी:
  पुश (बी)
  कूदो * आईपी ++
जोड़ना:
  परिणाम = पीओपी () + पीओपी ()
  पुश (परिणाम)
  कूदो * आईपी ++
</वाक्यविन्यास हाइलाइट>


वैकल्पिक रूप से, ऑपरेंड को थ्रेड में शामिल किया जा सकता है। यह उपरोक्त आवश्यक कुछ संकेतों को हटा सकता है, लेकिन धागे को बड़ा बनाता है:
[[स्टैक मशीन]] का एक उदाहरण अनुक्रम पुश ए, पुश बी, एड को निष्पादित कर सकता है। इसका अनुवाद निम्नलिखित थ्रेड और रूटीन में किया जा सकता है, जहाँ <code>ip</code> लेबल किए गए एड्रैस पर प्रारंभ किया गया है <code>thread</code> (यानी, पता जहां <code>&pushA</code> रखा है)।
 
#define PUSH(x) (*sp++ = (x))
<वाक्यविन्यास प्रकाश लैंग = सी>
#define POP() (*--sp)
#define पुश(x) (*sp++ = (x))
start:
#define POP() (*--sp)
  ip = &thread  // ip points to &pushA (which points to the first instruction of pushA)
शुरू करना:
  jump *ip++  // send control to first instruction of pushA and advance ip to &pushB
  आईपी ​​\u003d और धागा
thread:
  कूदो * आईपी ++
  &pushA
धागा:
  &pushB
  &धकेलना
  &add
  &// पता जहां ए संग्रहीत है, शाब्दिक ए नहीं
  ...
  &धकेलना
pushA:
  &बी
  PUSH(A)
  &जोड़ना
  jump *ip++ // send control where ip says to (i.e. to pushB) and advance ip
  ...
pushB:
धकेलना:
  PUSH(B)
  variable_address = *ip++ // आईपी को पिछले ऑपरेंड पते पर ले जाना चाहिए, क्योंकि यह एक सबरूटीन पता नहीं है
  jump *ip++
  PUSH(*variable_address) // वेरिएबल से वैल्यू पढ़ें और स्टैक पर पुश करें
add:
  कूदो * आईपी ++
  result = POP() + POP()
जोड़ना:
  PUSH(result)
  परिणाम = पीओपी () + पीओपी ()
  jump *ip++
  पुश (परिणाम)
वैकल्पिक रूप से, ऑपरेंड को थ्रेड में सम्मिलित किया जा सकता है। यह उपरोक्त आवश्यक कुछ संकेतों को हटा सकता है, लेकिन धागे को बड़ा बनाता है:
  कूदो * आईपी ++
#define PUSH(x) (*sp++ = (x))
</वाक्यविन्यास हाइलाइट>
#define POP() (*--sp)
start:
  ip = &thread
  jump *ip++
thread:
  &push
  &// address where A is stored, not literal A
  &push
  &B
  &add
  ...
push:
  variable_address = *ip++ // must move ip past operand address, since it is not a subroutine address
  PUSH(*variable_address) // Read value from variable and push on stack
  jump *ip++
add:
  result = POP() + POP()
  PUSH(result)
  jump *ip++


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


उदाहरण के लिए, यदि लक्ष्य पुश ए, पुश बी, ऐड निष्पादित करना है, तो निम्न का उपयोग किया जा सकता है। यहाँ, <code>ip</code> पता करने के लिए प्रारंभ किया गया है <code>&thread</code>, प्रत्येक कोड खंड (<code>push</code>, <code>add</code>) के माध्यम से डबल-इनडायरेक्टिंग द्वारा पाया जाता है <code>ip</code> और एक अप्रत्यक्ष ब्लॉक; और फ़्रैगमेंट के किसी भी ऑपरेंड को फ़्रैगमेंट के पते के बाद अप्रत्यक्ष ब्लॉक में पाया जाता है। इसके लिए वर्तमान सबरूटीन को अंदर रखने की आवश्यकता है <code>ip</code>, पिछले सभी उदाहरणों के विपरीत जहां इसमें अगले सबरूटीन को बुलाया जाना था।
उदाहरण के लिए, यदि लक्ष्य पुश ए, पुश बी, ऐड निष्पादित करना है, तो निम्न का उपयोग किया जा सकता है। यहाँ, <code>ip</code> पता करने के लिए प्रारंभ किया गया है <code>&thread</code>, प्रत्येक कोड खंड (<code>push</code>, <code>add</code>) के माध्यम से डबल-इनडायरेक्टिंग द्वारा पाया जाता है <code>ip</code> और एक अप्रत्यक्ष ब्लॉक; और फ़्रैगमेंट के किसी भी ऑपरेंड को फ़्रैगमेंट के एड्रैस के बाद अप्रत्यक्ष ब्लॉक में पाया जाता है। इसके लिए वर्तमान सबरूटीन को अंदर रखने की आवश्यकता है <code>ip</code>, पिछले सभी उदाहरणों के विपरीत जहां इसमें अगले सबरूटीन को बुलाया जाना था।
 
start:
<वाक्यविन्यास प्रकाश लैंग = सी>
  ip = &thread  // points to '&i_pushA'
शुरू करना:
  jump *(*ip) // follow pointers to 1st instruction of 'push', DO NOT advance ip yet
  आईपी ​​\u003d और धागा // 'और i_pushA' की ओर इशारा करता है
thread:
  जंप *(*आईपी) // 'पुश' के पहले निर्देश के लिए पॉइंटर्स का पालन करें, अभी तक आईपी को आगे न बढ़ाएं
  &i_pushA
धागा:
  &i_pushB
  &i_pushA
  &i_add
  &i_pushB
  ...
  &मैं जोड़ना
i_pushA:
  ...
  &push
i_pushA:
  &A
  &धकेलना
i_pushB:
  &
  &push
i_pushB:
  &B
  &धकेलना
i_add:
  &बी
  &add
मैं जोड़ना:
push:
  &जोड़ना
  *sp++ = *(*ip + 1) // look 1 past start of indirect block for operand address
धकेलना:
  jump *(*++ip) // advance ip in thread, jump through next indirect block to next subroutine
  *sp++ = *(*ip + 1) // ऑपरेंड एड्रेस के लिए अप्रत्यक्ष ब्लॉक के 1 अतीत की शुरुआत देखें
add:
  जंप *(*++ip) // थ्रेड में अग्रिम आईपी, अगले अप्रत्यक्ष ब्लॉक के माध्यम से अगले सबरूटीन में कूदें
  addend1 = *--sp
जोड़ना:
  addend2 = *--sp
  addend1 = *--sp
  *sp++ = addend1 + addend2
  addend2 = *--sp
  jump *(*++ip)
  *एसपी++ = एडेंड1 + एडेंड2
  कूदो *(*++आईपी)
</वाक्यविन्यास हाइलाइट>


=== सबरूटीन थ्रेडिंग ===
=== सबरूटीन थ्रेडिंग ===
तथाकथित सबरूटीन-थ्रेडेड कोड (कॉल-थ्रेडेड कोड भी) में मशीन-भाषा कॉल निर्देशों की एक श्रृंखला होती है (या सीधे थ्रेडिंग के जंप के उपयोग के विपरीत, कॉल करने के लिए फ़ंक्शन के पते)। [[ALGOL]], फोरट्रान, कोबोल और कुछ फोर्थ सिस्टम के शुरुआती कंपाइलर अक्सर सबरूटीन-थ्रेडेड कोड का उत्पादन करते थे। इनमें से कई प्रणालियों में कोड ऑपरेंड के लास्ट-इन-फर्स्ट-आउट (एलआईएफओ) स्टैक पर संचालित होता है, जिसके लिए कंपाइलर सिद्धांत अच्छी तरह से विकसित था। अधिकांश आधुनिक प्रोसेसर में सबरूटीन कॉल और रिटर्न निर्देशों के लिए विशेष हार्डवेयर समर्थन होता है, इसलिए प्रति प्रेषण एक अतिरिक्त मशीन निर्देश का ओवरहेड कुछ हद तक कम हो जाता है।
तथाकथित सबरूटीन-थ्रेडेड कोड (कॉल-थ्रेडेड कोड भी) में मशीन-भाषा कॉल निर्देशों की एक श्रृंखला होती है (या सीधे थ्रेडिंग के जंप के उपयोग के विपरीत, कॉल करने के लिए फ़ंक्शन के एड्रैस)। [[ALGOL|एल्गोरिथम भाषा]], फोरट्रान, सामान्य व्यवसाय उन्मुखी भाषा और कुछ फोर्थ सिस्टम के प्रारम्भिक कंपाइलर प्रायः सबरूटीन-थ्रेडेड कोड का उत्पादन करते थे। इनमें से कई प्रणालियों में कोड ऑपरेंड के लास्ट-इन-फर्स्ट-आउट (एलआईएफओ) स्टैक पर संचालित होता है, जिसके लिए कंपाइलर सिद्धांत अच्छी तरह से विकसित था। अधिकांश आधुनिक प्रोसेसर में सबरूटीन कॉल और रिटर्न निर्देशों के लिए विशेष हार्डवेयर समर्थन होता है, इसलिए प्रति प्रेषण एक अतिरिक्त मशीन निर्देश का ओवरहेड कुछ हद तक कम हो जाता है।


[[Gforth]] कंपाइलर के सह-निर्माता एंटोन एर्टल ने कहा कि लोकप्रिय मिथकों के विपरीत, सबरूटीन थ्रेडिंग आमतौर पर डायरेक्ट थ्रेडिंग की तुलना में धीमी होती है।<ref>{{cite web| url=http://www.complang.tuwien.ac.at/forth/threaded-code.html#what| title=What is Threaded Code?| first=Anton| last=Ertl}}</ref> हालाँकि, Ertl के सबसे हालिया परीक्षण<ref name="tuwien1"/>दिखाएँ कि 25 में से 15 परीक्षण मामलों में सबरूटीन थ्रेडिंग सीधे थ्रेडिंग से तेज़ है। अधिक विशेष रूप से, उन्होंने पाया कि डायरेक्ट थ्रेडिंग एक्सॉन, ओपर्टन और एथलॉन प्रोसेसर पर सबसे तेज़ थ्रेडिंग मॉडल है, पेंटियम एम प्रोसेसर पर अप्रत्यक्ष थ्रेडिंग सबसे तेज़ है, और सबरूटीन थ्रेडिंग पेंटियम 4, पेंटियम III और पीपीसी प्रोसेसर पर सबसे तेज़ है।
[[Gforth]] कंपाइलर के सह-निर्माता एंटोन एर्टल ने कहा कि लोकप्रिय मिथकों के विपरीत, सबरूटीन थ्रेडिंग सामान्य रूप से डायरेक्ट थ्रेडिंग की तुलना में धीमी होती है।<ref>{{cite web| url=http://www.complang.tuwien.ac.at/forth/threaded-code.html#what| title=What is Threaded Code?| first=Anton| last=Ertl}}</ref> हालाँकि, Ertl के सबसे हालिया परीक्षण<ref name="tuwien1"/>दिखाएँ कि 25 में से 15 परीक्षण मामलों में सबरूटीन थ्रेडिंग सीधे थ्रेडिंग से तेज़ है। अधिक विशेष रूप से, उन्होंने पाया कि डायरेक्ट थ्रेडिंग एक्सॉन, ओपर्टन और एथलॉन प्रोसेसर पर सबसे तेज़ थ्रेडिंग मॉडल है, पेंटियम एम प्रोसेसर पर अप्रत्यक्ष थ्रेडिंग सबसे तेज़ है, और सबरूटीन थ्रेडिंग पेंटियम 4, पेंटियम III और पीपीसी प्रोसेसर पर सबसे तेज़ है।


पुश A के लिए कॉल थ्रेडिंग के उदाहरण के रूप में, B को पुश करें, जोड़ें:
पुश A के लिए कॉल थ्रेडिंग के उदाहरण के रूप में, B को पुश करें, जोड़ें:
 
thread:
<वाक्यविन्यास प्रकाश लैंग = सी>
  call pushA
धागा:
  call pushB
  कॉल pushA
  call add
  कॉल पुश बी
  ret
  कॉल जोड़ें
pushA:
  गीला करना
  *sp++ = A
पुशा:
  ret
  *एसपी++ =
pushB:
  गीला करना
  *sp++ = B
पुशबी:
  ret
  *एसपी++ = बी
add:
  गीला करना
  addend1 = *--sp
जोड़ना:
  addend2 = *--sp
  addend1 = *--sp
  *sp++ = addend1 + addend2
  addend2 = *--sp
  ret
  *एसपी++ = एडेंड1 + एडेंड2
  गीला करना
</वाक्यविन्यास हाइलाइट>


=== टोकन थ्रेडिंग ===
=== टोकन थ्रेडिंग ===
टोकन-थ्रेडेड कोड संचालन की तालिका में सूचकांकों की सूची के रूप में थ्रेड को लागू करता है; घनत्व और दक्षता के लिए इंडेक्स चौड़ाई को स्वाभाविक रूप से जितना संभव हो उतना छोटा चुना [[जावा (प्रोग्रामिंग भाषा)]] में आसानी के लिए 1 बाइट / 8-बिट्स प्राकृतिक पसंद है, लेकिन 4-बिट्स जैसे छोटे आकार, या 12 या 16 बिट्स जैसे बड़े आकार का उपयोग समर्थित संचालन की संख्या के आधार पर किया जा सकता है। जब तक इंडेक्स की चौड़ाई को मशीन पॉइंटर की तुलना में संकरा चुना जाता है, तब तक यह प्रोग्रामर द्वारा विशेष प्रयास किए बिना स्वाभाविक रूप से अन्य थ्रेडिंग प्रकारों की तुलना में अधिक कॉम्पैक्ट होगा। यह आमतौर पर अन्य थ्रेडिंग के आकार का आधा से तीन-चौथाई होता है, जो स्वयं एक चौथाई से आठवें गैर-थ्रेडेड कोड के आकार का होता है। तालिका के संकेतक या तो अप्रत्यक्ष या प्रत्यक्ष हो सकते हैं। कुछ फोर्थ कंपाइलर्स टोकन-थ्रेडेड कोड उत्पन्न करते हैं। कुछ प्रोग्रामर [[पी-कोड मशीन]] | कुछ [[पास्कल (प्रोग्रामिंग भाषा)]] कंपाइलर्स द्वारा उत्पन्न पी-कोड, साथ ही साथ .NET Framework|.NET, Java (प्रोग्रामिंग लैंग्वेज), BASIC और कुछ C (प्रोग्रामिंग लैंग्वेज) द्वारा उपयोग किए जाने वाले [[बाईटकोड]]्स पर विचार करते हैं। संकलक, टोकन-थ्रेडिंग होना।
टोकन-थ्रेडेड कोड संचालन की तालिका में सूचकांकों की सूची के रूप में थ्रेड को लागू करता है; घनत्व और दक्षता के लिए इंडेक्स चौड़ाई को स्वाभाविक रूप से जितना संभव हो उतना छोटा चुना [[जावा (प्रोग्रामिंग भाषा)]] में आसानी के लिए 1 बाइट / 8-बिट्स प्राकृतिक पसंद है, लेकिन 4-बिट्स जैसे छोटे आकार, या 12 या 16 बिट्स जैसे बड़े आकार का उपयोग समर्थित संचालन की संख्या के आधार पर किया जा सकता है। जब तक इंडेक्स की चौड़ाई को मशीन पॉइंटर की तुलना में संकरा चुना जाता है, तब तक यह प्रोग्रामर द्वारा विशेष प्रयास किए बिना स्वाभाविक रूप से अन्य थ्रेडिंग प्रकारों की तुलना में अधिक कॉम्पैक्ट होगा। यह सामान्य रूप से अन्य थ्रेडिंग के आकार का आधा से तीन-चौथाई होता है, जो स्वयं एक चौथाई से आठवें गैर-थ्रेडेड कोड के आकार का होता है। तालिका के संकेतक या तो अप्रत्यक्ष या प्रत्यक्ष हो सकते हैं। कुछ फोर्थ कंपाइलर्स टोकन-थ्रेडेड कोड उत्पन्न करते हैं। कुछ प्रोग्रामर [[पी-कोड मशीन]] | कुछ [[पास्कल (प्रोग्रामिंग भाषा)]] कंपाइलर्स द्वारा उत्पन्न पी-कोड, साथ ही साथ .NET Framework|.NET, Java (प्रोग्रामिंग लैंग्वेज), सामान्य संयुक्त प्रोग्रामिंग भाषा और कुछ C (प्रोग्रामिंग लैंग्वेज) द्वारा उपयोग किए जाने वाले [[बाईटकोड]]्स पर विचार करते हैं। संकलक, टोकन-थ्रेडिंग होना।


एक सामान्य दृष्टिकोण, ऐतिहासिक रूप से, बायटेकोड है, जो आमतौर पर स्टैक-आधारित वर्चुअल मशीन के साथ 8-बिट ऑपकोड का उपयोग करता है। मूलप्ररूपी बायटेकोड इंटरप्रेटर (कंप्यूटिंग) को डिकोड और डिस्पैच दुभाषिया के रूप में जाना जाता है और यह इस प्रकार है:
एक सामान्य दृष्टिकोण, ऐतिहासिक रूप से, बायटेकोड है, जो सामान्य रूप से स्टैक-आधारित वर्चुअल मशीन के साथ 8-बिट ऑपकोड का उपयोग करता है। मूलप्ररूपी बायटेकोड इंटरप्रेटर (कंप्यूटिंग) को डिकोड और डिस्पैच दुभाषिया के रूप में जाना जाता है और यह इस प्रकार है:
start:
  vpc = &thread
dispatch:
  addr = decode(&vpc) // Convert the next bytecode operation to a pointer to machine code that implements it
  // Any inter-instruction operations are performed here (e.g. updating global state, event processing, etc)
  jump addr
CODE_PTR decode(BYTE_CODE **p) {
  // In a more complex encoding, there may be multiple tables to choose between or control/mode flags
  return table[*(*p)++];
}
thread:  /* Contains bytecode, not machine addresses.  Hence it is more compact. */
  1 /*pushA*/
  2 /*pushB*/
  0 /*add*/
table:
  &add    /* table[0] = address of machine code that implements bytecode 0 */
  &pushA  /* table[1] ... */
  &pushB  /* table[2] ... */
pushA:
  *sp++ = A
  jump dispatch
pushB:
  *sp++ = B
  jump dispatch
add:
  addend1 = *--sp
  addend2 = *--sp
  *sp++ = addend1 + addend2
  jump dispatch
यदि वर्चुअल मशीन केवल बाइट-आकार के निर्देशों का उपयोग करती है, <code>decode()</code> बस से लाया गया है <code>thread</code>, लेकिन प्रायः सामान्य रूप से 1-बाइट निर्देशों का उपयोग किया जाता है और कुछ कम-सामान्य मल्टीबाइट निर्देश ([[जटिल निर्देश सेट कंप्यूटर]] देखें), जिस स्थिति में <code>decode()</code> अधिक जटिल है। एकल बाइट ऑपकोड का डिकोडिंग बहुत ही सरलता से और कुशलता से एक शाखा तालिका द्वारा सीधे एक इंडेक्स के रूप में ऑपकोड का उपयोग करके किया जा सकता है।


<वाक्यविन्यास प्रकाश लैंग = सी>
निर्देशों के लिए जहां व्यक्तिगत संचालन सरल होते हैं, जैसे कि पुश और ऐड, क्या निष्पादित करना है, यह तय करने में सम्मिलित [[कम्प्यूटेशनल ओवरहेड]] वास्तव में इसे निष्पादित करने की लागत से बड़ा है, इसलिए ऐसे दुभाषिए प्रायः मशीन कोड की तुलना में बहुत धीमे होते हैं। हालांकि, अधिक जटिल (यौगिक) निर्देशों के लिए, ओवरहेड प्रतिशत आनुपातिक रूप से कम महत्वपूर्ण है।
शुरू करना:
  वीपीसी = और थ्रेड
प्रेषण:
  Addr = decode(&vpc) // अगले बायटेकोड ऑपरेशन को पॉइंटर से मशीन कोड में बदलें जो इसे लागू करता है
  // कोई भी इंटर-इंस्ट्रक्शन ऑपरेशंस यहां पर किए जाते हैं (जैसे ग्लोबल स्टेट अपडेट करना, इवेंट प्रोसेसिंग आदि)
  कूदो
CODE_PTR डिकोड (BYTE_CODE **p) {
  // अधिक जटिल एन्कोडिंग में, चुनने या नियंत्रण/मोड फ़्लैग के बीच चुनने के लिए कई टेबल हो सकते हैं
  वापसी तालिका [* (* पी) ++];
}
थ्रेड: / * में बायटेकोड होता है, न कि मशीन के पते। इसलिए यह अधिक सघन है। */
  1 /*पुषा*/
  2 /*पुशबी*/
  0 /*जोड़ें*/
मेज:
  &जोड़ें /* टेबल[0] = मशीन कोड का पता जो बाईटेकोड 0 लागू करता है */
  और पुशा /* टेबल[1] ... */
  और पुशबी /* तालिका [2] ... */
पुशा:
  *एसपी++ = ए
  कूद प्रेषण
पुशबी:
  *एसपी++ = बी
  कूद प्रेषण
जोड़ना:
  addend1 = *--sp
  addend2 = *--sp
  *एसपी++ = एडेंड1 + एडेंड2
  कूद प्रेषण
</वाक्यविन्यास हाइलाइट>


यदि वर्चुअल मशीन केवल बाइट-आकार के निर्देशों का उपयोग करती है, <code>decode()</code> बस से लाया गया है <code>thread</code>, लेकिन अक्सर आमतौर पर 1-बाइट निर्देशों का उपयोग किया जाता है और कुछ कम-सामान्य मल्टीबाइट निर्देश ([[जटिल निर्देश सेट कंप्यूटर]] देखें), जिस स्थिति में <code>decode()</code> अधिक जटिल है। एकल बाइट ऑपकोड का डिकोडिंग बहुत ही सरलता से और कुशलता से एक शाखा तालिका द्वारा सीधे एक इंडेक्स के रूप में ऑपकोड का उपयोग करके किया जा सकता है।
ऐसे समय होते हैं जब टोकन-थ्रेडेड कोड कभी-कभी समतुल्य मशीन कोड की तुलना में तेजी से चल सकता है जब वह मशीन कोड भौतिक सेंट्रल प्रोसेसिंग यूनिट के L1 निर्देश कैश में फ़िट होने के लिए बहुत बड़ा हो जाता है। थ्रेडेड कोड का उच्च कोड घनत्व, विशेष रूप से टोकन-थ्रेडेड कोड, इसे L1 कैश में पूरी तरह से फिट होने की अनुमति दे सकता है, जब यह अन्यथा नहीं होता, जिससे कैश थ्रैशिंग से बचा जा सकता है। हालाँकि, थ्रेडेड कोड निर्देश कैश (प्रत्येक ऑपरेशन के कार्यान्वयन के लिए) के साथ-साथ डेटा कैश (बायटेकोड और टेबल के लिए) दोनों का उपभोग करता है, मशीन कोड के विपरीत जो केवल निर्देश कैश का उपभोग करता है; इसका मतलब है कि थ्रेडेड कोड किसी भी समय सीपीयू द्वारा प्रसंस्करण के लिए रखे जा सकने वाले डेटा की मात्रा के लिए बजट में खाएगा। किसी भी मामले में, यदि गणना की जा रही समस्या में डेटा की एक छोटी मात्रा में बड़ी संख्या में ऑपरेशन लागू करना सम्मिलित है, तो थ्रेडेड कोड का उपयोग करना एक आदर्श अनुकूलन हो सकता है।
<ref name="heller" />


निर्देशों के लिए जहां व्यक्तिगत संचालन सरल होते हैं, जैसे कि पुश और ऐड, क्या निष्पादित करना है, यह तय करने में शामिल [[कम्प्यूटेशनल ओवरहेड]] वास्तव में इसे निष्पादित करने की लागत से बड़ा है, इसलिए ऐसे दुभाषिए अक्सर मशीन कोड की तुलना में बहुत धीमे होते हैं। हालांकि, अधिक जटिल (यौगिक) निर्देशों के लिए, ओवरहेड प्रतिशत आनुपातिक रूप से कम महत्वपूर्ण है।
ऐसे समय होते हैं जब टोकन-थ्रेडेड कोड कभी-कभी समतुल्य मशीन कोड की तुलना में तेजी से चल सकता है जब वह मशीन कोड भौतिक CPU के L1 निर्देश कैश में फ़िट होने के लिए बहुत बड़ा हो जाता है। थ्रेडेड कोड का उच्च कोड घनत्व, विशेष रूप से टोकन-थ्रेडेड कोड, इसे L1 कैश में पूरी तरह से फिट होने की अनुमति दे सकता है, जब यह अन्यथा नहीं होता, जिससे कैश थ्रैशिंग से बचा जा सकता है। हालाँकि, थ्रेडेड कोड निर्देश कैश (प्रत्येक ऑपरेशन के कार्यान्वयन के लिए) के साथ-साथ डेटा कैश (बायटेकोड और टेबल के लिए) दोनों का उपभोग करता है, मशीन कोड के विपरीत जो केवल निर्देश कैश का उपभोग करता है; इसका मतलब है कि थ्रेडेड कोड किसी भी समय सीपीयू द्वारा प्रसंस्करण के लिए रखे जा सकने वाले डेटा की मात्रा के लिए बजट में खाएगा। किसी भी मामले में, यदि गणना की जा रही समस्या में डेटा की एक छोटी मात्रा में बड़ी संख्या में ऑपरेशन लागू करना शामिल है, तो थ्रेडेड कोड का उपयोग करना एक आदर्श अनुकूलन हो सकता है।
<ref name="heller"/>




Line 270: Line 243:
हफ़मैन थ्रेडेड कोड में [[हफ़मैन कोड]] के रूप में संग्रहीत टोकन की सूची होती है। एक हफ़मैन कोड बिट्स की एक चर-लंबाई वाली स्ट्रिंग है जो एक अद्वितीय टोकन की पहचान करती है। एक हफ़मैन-थ्रेडेड दुभाषिया इंडेक्स टेबल या पॉइंटर्स के एक पेड़ का उपयोग करके सबरूटीन्स का पता लगाता है जिसे हफ़मैन कोड द्वारा नेविगेट किया जा सकता है। हफमैन-थ्रेडेड कोड कंप्यूटर प्रोग्राम के लिए ज्ञात सबसे कॉम्पैक्ट प्रतिनिधित्वों में से एक है। कोड में प्रत्येक सबरूटीन को कॉल की आवृत्ति को मापकर इंडेक्स और कोड चुने जाते हैं। बार-बार कॉल करने के लिए सबसे छोटा कोड दिया जाता है। लगभग समान आवृत्तियों वाले संक्रियाओं को लगभग समान बिट-लंबाई वाले कोड दिए जाते हैं। अधिकांश हफ़मैन-थ्रेडेड सिस्टम को डायरेक्ट-थ्रेडेड फोर्थ सिस्टम के रूप में लागू किया गया है, और बड़ी मात्रा में धीमी गति से चलने वाले कोड को छोटे, सस्ते [[microcontroller]] में पैक करने के लिए उपयोग किया जाता है। सर्वाधिक प्रकाशित<ref name=huffman>{{cite book |last1=Latendresse |first1=Mario |last2=Feeley |first2=Marc |title=Generation of Fast Interpreters for Huffman-Compressed Bytecode |citeseerx=10.1.1.156.2546 |publisher=Elsevier}}</ref> उपयोग स्मार्ट कार्ड, खिलौने, कैलकुलेटर और घड़ियों में किया गया है। [[PBASIC]] में उपयोग किए जाने वाले बिट-ओरिएंटेड टोकन कोड को एक प्रकार के हफ़मैन-थ्रेडेड कोड के रूप में देखा जा सकता है।
हफ़मैन थ्रेडेड कोड में [[हफ़मैन कोड]] के रूप में संग्रहीत टोकन की सूची होती है। एक हफ़मैन कोड बिट्स की एक चर-लंबाई वाली स्ट्रिंग है जो एक अद्वितीय टोकन की पहचान करती है। एक हफ़मैन-थ्रेडेड दुभाषिया इंडेक्स टेबल या पॉइंटर्स के एक पेड़ का उपयोग करके सबरूटीन्स का पता लगाता है जिसे हफ़मैन कोड द्वारा नेविगेट किया जा सकता है। हफमैन-थ्रेडेड कोड कंप्यूटर प्रोग्राम के लिए ज्ञात सबसे कॉम्पैक्ट प्रतिनिधित्वों में से एक है। कोड में प्रत्येक सबरूटीन को कॉल की आवृत्ति को मापकर इंडेक्स और कोड चुने जाते हैं। बार-बार कॉल करने के लिए सबसे छोटा कोड दिया जाता है। लगभग समान आवृत्तियों वाले संक्रियाओं को लगभग समान बिट-लंबाई वाले कोड दिए जाते हैं। अधिकांश हफ़मैन-थ्रेडेड सिस्टम को डायरेक्ट-थ्रेडेड फोर्थ सिस्टम के रूप में लागू किया गया है, और बड़ी मात्रा में धीमी गति से चलने वाले कोड को छोटे, सस्ते [[microcontroller]] में पैक करने के लिए उपयोग किया जाता है। सर्वाधिक प्रकाशित<ref name=huffman>{{cite book |last1=Latendresse |first1=Mario |last2=Feeley |first2=Marc |title=Generation of Fast Interpreters for Huffman-Compressed Bytecode |citeseerx=10.1.1.156.2546 |publisher=Elsevier}}</ref> उपयोग स्मार्ट कार्ड, खिलौने, कैलकुलेटर और घड़ियों में किया गया है। [[PBASIC]] में उपयोग किए जाने वाले बिट-ओरिएंटेड टोकन कोड को एक प्रकार के हफ़मैन-थ्रेडेड कोड के रूप में देखा जा सकता है।


==={{anchor|String threading}}कम उपयोग की जाने वाली थ्रेडिंग ===
===कम उपयोग की जाने वाली थ्रेडिंग ===
एक उदाहरण स्ट्रिंग थ्रेडिंग है, जिसमें संचालन को स्ट्रिंग्स द्वारा पहचाना जाता है, आमतौर पर हैश टेबल द्वारा देखा जाता है। इसका उपयोग चार्ल्स एच. मूर के शुरुआती फोर्थ कार्यान्वयन और इलिनोइस विश्वविद्यालय में उरबाना-चैंपियन के प्रयोगात्मक हार्डवेयर-व्याख्या कंप्यूटर भाषा में किया गया था। इसका उपयोग [[बेशफर्थ]] में भी किया जाता है।
एक उदाहरण स्ट्रिंग थ्रेडिंग है, जिसमें संचालन को स्ट्रिंग्स द्वारा पहचाना जाता है, सामान्य रूप से हैश टेबल द्वारा देखा जाता है। इसका उपयोग चार्ल्स एच. मूर के प्रारम्भिक फोर्थ कार्यान्वयन और इलिनोइस विश्वविद्यालय में उरबाना-चैंपियन के प्रयोगात्मक हार्डवेयर-व्याख्या कंप्यूटर भाषा में किया गया था। इसका उपयोग [[बेशफर्थ]] में भी किया जाता है।


===आरपीएल ===
===आरपीएल ===


[[Hewlett-Packard]] की RPL (प्रोग्रामिंग लैंग्वेज), जिसे पहली बार 1986 में [[HP-18C]] कैलकुलेटर में पेश किया गया था, एक प्रकार का मालिकाना हाइब्रिड डायरेक्ट-थ्रेडेड और इनडायरेक्ट-थ्रेडेड थ्रेडेड-इंटरप्रिटेड लैंग्वेज है, जो अन्य TILs के विपरीत, RPL ऑब्जेक्ट्स को एम्बेड करने की अनुमति देता है। रनस्ट्रीम यानी। पतों की धारा जिसके माध्यम से दुभाषिया सूचक आगे बढ़ता है। एक आरपीएल ऑब्जेक्ट को एक विशेष डेटा प्रकार के रूप में माना जा सकता है जिसकी इन-मेमोरी संरचना में ऑब्जेक्ट की शुरुआत में ऑब्जेक्ट प्रोलॉग का पता होता है, और उसके बाद डेटा या निष्पादन योग्य कोड होता है। ऑब्जेक्ट प्रोलॉग निर्धारित करता है कि ऑब्जेक्ट के शरीर को कैसे निष्पादित या संसाधित किया जाना चाहिए। आरपीएल इनर लूप का उपयोग करना,<ref name="RPL1">Busby, Jonathan. [https://www.hpmuseum.org/forum/thread-11358.html "The RPL inner loop explained"], [http://www.hpmuseum.org/ "The Museum of HP Calculators"], 7 September 2018, Retrieved on 27 December 2019</ref> जिसका आविष्कार और प्रकाशन किया गया था (और पेटेंट कराया गया था <ref>{{cite web | last = Wickes | first = William C. | title = Data processing system and method for the direct and indirect execution of uniformly structured object types | website = uspto.gov | date = May 30, 1986 | url = http://patft.uspto.gov/netacgi/nph-Parser?Sect1=PTO2&Sect2=HITOFF&u=%2Fnetahtml%2FPTO%2Fsearch-adv.htm&r=8&p=1&f=G&l=50&d=PTXT&S1=((%22Hewlett+Packard%22.ASNM.)+AND+Wickes.INNM.)&OS=AN/%22Hewlett+Packard%22+and+IN/Wickes&RS=(AN/%22Hewlett+Packard%22+AND+IN/Wickes) | access-date = December 27, 2019 }}</ref>) 1986 में विलियम सी. विकेस द्वारा और प्रोग्रामिंग एनवायरनमेंट, इंस्टीट्यूट फॉर एप्लाइड फोर्थ रिसर्च, इंक., 1988 में प्रकाशित, निष्पादन इस प्रकार है:
[[Hewlett-Packard]] की RPL (प्रोग्रामिंग लैंग्वेज), जिसे पहली बार 1986 में [[HP-18C]] कैलकुलेटर में पेश किया गया था, एक प्रकार का मालिकाना हाइब्रिड डायरेक्ट-थ्रेडेड और इनडायरेक्ट-थ्रेडेड थ्रेडेड-इंटरप्रिटेड लैंग्वेज है, जो अन्य TILs के विपरीत, RPL ऑब्जेक्ट्स को एम्बेड करने की अनुमति देता है। रनस्ट्रीम यानी। पतों की धारा जिसके माध्यम से दुभाषिया सूचक आगे बढ़ता है। एक आरपीएल ऑब्जेक्ट को एक विशेष डेटा प्रकार के रूप में माना जा सकता है जिसकी इन-मेमोरी संरचना में ऑब्जेक्ट की प्रारंभ में ऑब्जेक्ट प्रोलॉग का पता होता है, और उसके बाद डेटा या निष्पादन योग्य कोड होता है। ऑब्जेक्ट प्रोलॉग निर्धारित करता है कि ऑब्जेक्ट के शरीर को कैसे निष्पादित या संसाधित किया जाना चाहिए। आरपीएल इनर लूप का उपयोग करना,<ref name="RPL1">Busby, Jonathan. [https://www.hpmuseum.org/forum/thread-11358.html "The RPL inner loop explained"], [http://www.hpmuseum.org/ "The Museum of HP Calculators"], 7 September 2018, Retrieved on 27 December 2019</ref> जिसका आविष्कार और प्रकाशन किया गया था (और पेटेंट कराया गया था <ref>{{cite web | last = Wickes | first = William C. | title = Data processing system and method for the direct and indirect execution of uniformly structured object types | website = uspto.gov | date = May 30, 1986 | url = http://patft.uspto.gov/netacgi/nph-Parser?Sect1=PTO2&Sect2=HITOFF&u=%2Fnetahtml%2FPTO%2Fsearch-adv.htm&r=8&p=1&f=G&l=50&d=PTXT&S1=((%22Hewlett+Packard%22.ASNM.)+AND+Wickes.INNM.)&OS=AN/%22Hewlett+Packard%22+and+IN/Wickes&RS=(AN/%22Hewlett+Packard%22+AND+IN/Wickes) | access-date = December 27, 2019 }}</ref>) 1986 में विलियम सी. विकेस द्वारा और प्रोग्रामिंग एनवायरनमेंट, इंस्टीट्यूट फॉर एप्लाइड फोर्थ रिसर्च, इंक., 1988 में प्रकाशित, निष्पादन इस प्रकार है:


# IP (निर्देश सूचक) को हटा दें और इसे O (वर्तमान ऑब्जेक्ट पॉइंटर) में संग्रहीत करें
# IP (निर्देश सूचक) को हटा दें और इसे O (वर्तमान ऑब्जेक्ट पॉइंटर) में संग्रहीत करें
# आईपी को एक एड्रेस पॉइंटर की लंबाई से बढ़ाएं
# आईपी को एक एड्रेस पॉइंटर की लंबाई से बढ़ाएं
# Dereference O और इसके पते को O_1 में संग्रहीत करें (यह संकेत का दूसरा स्तर है)
# Dereference O और इसके एड्रैस को O_1 में संग्रहीत करें (यह संकेत का दूसरा स्तर है)
# पीसी (प्रोग्राम काउंटर) को O_1 प्लस एक एड्रेस पॉइंटर पर सेट करके अगले पॉइंटर या एम्बेडेड ऑब्जेक्ट पर नियंत्रण स्थानांतरित करें
# पीसी (प्रोग्राम काउंटर) को O_1 प्लस एक एड्रेस पॉइंटर पर सेट करके अगले पॉइंटर या एम्बेडेड ऑब्जेक्ट पर नियंत्रण स्थानांतरित करें
# चरण 1 पर वापस जाएं
# चरण 1 पर वापस जाएं
Line 285: Line 258:
यह अधिक सटीक रूप से प्रतिनिधित्व कर सकता है:
यह अधिक सटीक रूप से प्रतिनिधित्व कर सकता है:


<पूर्व>
    O  = [I]
    ओ = [मैं]
 
    मैं = मैं + Δ
    I  = I + Δ
    पीसी = [] + Δ
    PC = [O] + Δ
</पूर्व>


जहाँ ऊपर, O वर्तमान ऑब्जेक्ट पॉइंटर है, I इंटरप्रेटर पॉइंटर है, Δ एक एड्रेस शब्द की लंबाई है और [] ऑपरेटर dereference के लिए खड़ा है।
जहाँ ऊपर, O वर्तमान ऑब्जेक्ट पॉइंटर है, I इंटरप्रेटर पॉइंटर है, Δ एक एड्रेस शब्द की लंबाई है और [] ऑपरेटर dereference के लिए खड़ा है।
Line 296: Line 268:


<पूर्व>
<पूर्व>
PROLOG -> PROLOG (प्रोलॉग कोड की शुरुआत में प्रोलॉग पता खुद को इंगित करता है)
PROLOG -> PROLOG (प्रोलॉग कोड की प्रारंभ में प्रोलॉग पता खुद को इंगित करता है)
     अगर ओ + Δ =/= पीसी
     PROLOG -> PROLOG ( The prolog address at the start of the prolog code points to itself )
    फिर गोटो अप्रत्यक्ष (प्रत्यक्ष निष्पादन के लिए परीक्षण)
 
        ओ = आई - Δ (एम्बेडेड ऑब्जेक्ट की शुरुआत को इंगित करने के लिए सही ओ)
    IF O + Δ =/= PC
        I = I + α (एम्बेडेड ऑब्जेक्ट के बाद इंगित करने के लिए सही करें जहां α ऑब्जेक्ट की लंबाई है)
    THEN GOTO INDIRECT ( Test for direct execution )
    अप्रत्यक्ष (बाकी प्रोलॉग)
        O = I - Δ ( Correct O to point to start of embedded object )
</पूर्व>
        I = I + α ( Correct I to point after embedded object where α is the length of the object )
    INDIRECT ( rest of prolog )


एचपी के [[एचपी शनि]] माइक्रोप्रोसेसरों पर जो आरपीएल का उपयोग करते हैं, एक वास्तुशिल्प/प्रोग्रामिंग ट्रिक द्वारा संभव बनाया गया एक तीसरा स्तर है जो तेजी से निष्पादन की अनुमति देता है।<ref name="RPL1"/>
एचपी के [[एचपी शनि]] माइक्रोप्रोसेसरों पर जो आरपीएल का उपयोग करते हैं, एक वास्तुशिल्प/प्रोग्रामिंग ट्रिक द्वारा संभव बनाया गया एक तीसरा स्तर है जो तेजी से निष्पादन की अनुमति देता है।<ref name="RPL1"/>
Line 308: Line 281:


== शाखाएँ ==
== शाखाएँ ==
सभी दुभाषियों में, एक शाखा केवल थ्रेड पॉइंटर (<code>ip</code>) थ्रेड में किसी भिन्न पते पर। एक कंडीशनल जंप-इफ-जीरो ब्रांच जो केवल तभी जंप करती है जब टॉप-ऑफ-स्टैक वैल्यू शून्य हो, जैसा कि नीचे दिखाया गया है। यह उदाहरण डायरेक्ट थ्रेडिंग के एम्बेडेड पैरामीटर संस्करण का उपयोग करता है ताकि <code>&thread[123]</code> लाइन वह गंतव्य है जहां स्थिति सही होने पर कूदना है, इसलिए इसे छोड़ दिया जाना चाहिए (<code>ip++</code>) खत्म अगर शाखा नहीं ली जाती है।
सभी दुभाषियों में, एक शाखा केवल थ्रेड पॉइंटर (<code>ip</code>) थ्रेड में किसी भिन्न एड्रैस पर। एक कंडीशनल जंप-इफ-जीरो ब्रांच जो केवल तभी जंप करती है जब टॉप-ऑफ-स्टैक वैल्यू शून्य हो, जैसा कि नीचे दिखाया गया है। यह उदाहरण डायरेक्ट थ्रेडिंग के एम्बेडेड पैरामीटर संस्करण का उपयोग करता है ताकि <code>&thread[123]</code> लाइन वह गंतव्य है जहां स्थिति सही होने पर कूदना है, इसलिए इसे छोड़ दिया जाना चाहिए (<code>ip++</code>) खत्म अगर शाखा नहीं ली जाती है।
 
thread:
<वाक्यविन्यास प्रकाश लैंग = सी>
  ...
धागा:
  &brz
  ...
  &thread[123]
  &brz
  ...
  & धागा [123]
brz:
  ...
  when_true_ip = *ip++ // Get destination address for branch
ब्रज़:
  if (*--sp == 0)     // Pop/Consume top of stack and check if it's zero
  when_true_ip = *ip++ // शाखा के लिए गंतव्य पता प्राप्त करें
    ip = when_true_ip
  if (*--sp == 0) // स्टैक के शीर्ष पर पॉप/उपभोग करें और जांचें कि क्या यह शून्य है
  jump *ip++
    आईपी ​​​​= जब_true_ip
  कूदो * आईपी ++
</वाक्यविन्यास हाइलाइट>


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


थ्रेडेड वर्चुअल मशीन में अक्सर तीन [[प्रोसेसर रजिस्टर]] मौजूद होते हैं। सबरूटीन्स ('शब्द') के बीच डेटा पास करने के लिए एक और मौजूद है। ये:
थ्रेडेड वर्चुअल मशीन में प्रायः तीन [[प्रोसेसर रजिस्टर]] सम्मिलित होते हैं। सबरूटीन्स ('शब्द') के बीच डेटा पास करने के लिए एक और सम्मिलित है। ये:
* वर्चुअल मशीन का आईपी या आई ([[निर्देश सूचक]]) (वीएम को लागू करने वाले अंतर्निहित हार्डवेयर के [[कार्यक्रम गणक]] के साथ भ्रमित नहीं होना चाहिए)
* वर्चुअल मशीन का आईपी या आई ([[निर्देश सूचक]]) (वीएम को लागू करने वाले अंतर्निहित हार्डवेयर के [[कार्यक्रम गणक]] के साथ भ्रमित नहीं होना चाहिए)
* डब्ल्यू (कार्य सूचक)
* डब्ल्यू (कार्य सूचक)
Line 332: Line 302:
* एसपी या एस (शब्दों के बीच [[पैरामीटर]] पास करने के लिए पैरामीटर स्टैक पॉइंटर)
* एसपी या एस (शब्दों के बीच [[पैरामीटर]] पास करने के लिए पैरामीटर स्टैक पॉइंटर)


अक्सर, थ्रेडेड वर्चुअल मशीन, जैसे फोर्थ के कार्यान्वयन में, दिल में एक साधारण वर्चुअल मशीन होती है, जिसमें तीन आदिम होते हैं। वे हैं:
प्रायः, थ्रेडेड वर्चुअल मशीन, जैसे फोर्थ के कार्यान्वयन में, दिल में एक साधारण वर्चुअल मशीन होती है, जिसमें तीन आदिम होते हैं। वे हैं:
# घोंसला, जिसे डोकोल भी कहा जाता है
# घोंसला, जिसे डोकोल भी कहा जाता है
# unnest, या semi_s (;s)
# unnest, या semi_s (;s)
Line 338: Line 308:


अप्रत्यक्ष-थ्रेडेड वर्चुअल मशीन में, यहाँ दिए गए ऑपरेशन हैं:
अप्रत्यक्ष-थ्रेडेड वर्चुअल मशीन में, यहाँ दिए गए ऑपरेशन हैं:
<वाक्यविन्यास प्रकाश लैंग = सी>
  next:
अगला:
    *ip++ -> w
  * आईपी ++ -> डब्ल्यू
    jump **w++
  कूदो ** डब्ल्यू ++
  nest:
घोंसला:
    ip -> *rp++
  आईपी ​​-> * आरपी ++
    w -> ip
  डब्ल्यू -> आईपी
    next
  अगला
  unnest:
अननेस्ट:
    *--rp -> ip
  *--आरपी -> आईपी
    next
  अगला
</वाक्यविन्यास हाइलाइट>


== यह भी देखें ==
== यह भी देखें ==
{{Portal|Computer programming}}
{{Portal|Computer programming}}
* [[निरंतरता-गुजरने की शैली]], जो ग्लोबल वेरिएबल को रिप्लेस करता है <code>ip</code> एक समारोह पैरामीटर के साथ
* [[निरंतरता-गुजरने की शैली]], जो ग्लोबल वेरिएबल को रिप्लेस करता है <code>ip</code> एक फ़ंक्शन पैरामीटर के साथ
* अभी-अभी संकलन
* अभी-अभी संकलन
* [[वापसी-उन्मुख प्रोग्रामिंग]]: दूरस्थ कमजोर प्रणालियों का फायदा उठाने के लिए थ्रेडेड कोड की पुनर्खोज।
* [[वापसी-उन्मुख प्रोग्रामिंग]]: दूरस्थ कमजोर प्रणालियों का फायदा उठाने के लिए थ्रेडेड कोड की पुनर्खोज।

Revision as of 11:55, 24 February 2023

मल्टी-थ्रेडेड प्रोग्रामिंग या जंप थ्रेडिंग से भ्रमित न हों।

कंप्यूटर विज्ञान में, थ्रेडेड कोड एक प्रोग्रामिंग तकनीक है जहां स्रोत कोड का एक रूप होता है जो अनिवार्य रूप से पूरी तरह से सबरूटीन्स को कॉल करता है। यह प्रायः संकलक्स में प्रयोग किया जाता है, जो उस रूप में कोड उत्पन्न कर सकता है या स्वयं उस रूप में कार्यान्वित किया जा सकता है। कोड को दुभाषिया (कंप्यूटिंग) द्वारा संसाधित किया जा सकता है या यह केवल मशीन कोड कॉल निर्देशों का अनुक्रम हो सकता है।

थ्रेडेड कोड में वैकल्पिक पीढ़ी तकनीकों और वैकल्पिक कॉलिंग सम्मेलनों द्वारा उत्पन्न कोड की तुलना में बेहतर कोड घनत्व होता है। कैश (कंप्यूटिंग) आर्किटेक्चर में, यह निष्पादन (कंप्यूटिंग) थोड़ा धीमा हो सकता है।[citation needed] हालाँकि, एक प्रोग्राम जो एक कंप्यूटर प्रोसेसर के सेंट्रल प्रोसेसिंग यूनिट कैश में फिट होने के लिए काफी छोटा है, एक बड़े प्रोग्राम की तुलना में तेजी से चल सकता है जो कई कैश मिस से ग्रस्त है।[1] धागा स्विचिंग पर छोटे प्रोग्राम भी तेज़ हो सकते हैं, जब अन्य प्रोग्राम कैश भर चुके हों।

थ्रेडेड कोड को प्रोग्रामिंग भाषा के कई कंपाइलरों में इसके उपयोग के लिए जाना जाता है, जैसे फोर्थ (प्रोग्रामिंग भाषा), बुनियादी के कई कार्यान्वयन, सामान्य व्यवसाय उन्मुखी भाषा के कुछ कार्यान्वयन, B के प्रारम्भिक संस्करण (प्रोग्रामिंग लैंग्वेज),[2] और छोटे मिनी कंप्यूटर और शौकिया रेडियो उपग्रहों के लिए अन्य भाषाएं।[citation needed]


इतिहास

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

प्रारम्भिक कंप्यूटरों में अपेक्षाकृत कम मेमोरी होती थी। उदाहरण के लिए, अधिकांश दिनांक जनरल नोवा, IBM 1130, और कई पहले माइक्रो कंप्यूटरों में केवल 4 kB RAM स्थापित थी। नतीजतन, उपलब्ध मेमोरी में फिट होने के लिए प्रोग्राम के आकार को कम करने के तरीके खोजने की कोशिश में बहुत समय व्यतीत हुआ।

एक समाधान एक दुभाषिया का उपयोग करना है जो एक समय में प्रतीकात्मक भाषा को थोड़ा पढ़ता है, और कार्यों को करने के लिए कार्यों को बुलाता है। चूंकि स्रोत कोड सामान्य रूप से परिणामी मशीन कोड की तुलना में अधिक कोड घनत्व होता है, यह समग्र मेमोरी उपयोग को कम कर सकता है। यही कारण था कि Microsoft सामान्य संयुक्त प्रोग्रामिंग भाषा एक दुभाषिया है:[lower-alpha 1] इसके अपने कोड को Altair 8800 जैसी मशीनों की 4 kB मेमोरी को उपयोगकर्ता के स्रोत कोड के साथ साझा करना था। एक कंपाइलर सोर्स लैंग्वेज से मशीन कोड में ट्रांसलेट होता है, इसलिए कंपाइलर, सोर्स और आउटपुट सभी एक ही समय में मेमोरी में होने चाहिए। एक दुभाषिया में, कोई आउटपुट नहीं होता है।

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

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

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

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

थ्रेडेड कोड सिस्टम फ़ंक्शन कॉल की उस सूची को बदलकर कमरे को बचाते हैं, जहां निष्पादन टोकन की सूची के साथ केवल सबरूटीन पता एक कॉल से दूसरे कॉल में बदलता है, जो अनिवार्य रूप से कॉल ऑपकोड (ओं) के साथ फ़ंक्शन कॉल होते हैं, पीछे छोड़ देते हैं केवल पतों की एक सूची।[3][4][5][6][7] इन वर्षों में, प्रोग्रामर ने उस दुभाषिया या छोटे चयनकर्ता पर कई बदलाव किए हैं। पतों की सूची में विशेष पता एक इंडेक्स, सामान्य प्रयोजन रजिस्टर या सूचक (कंप्यूटर प्रोग्रामिंग) का उपयोग करके निकाला जा सकता है। एड्रैस प्रत्यक्ष या अप्रत्यक्ष, सन्निहित या गैर-सन्निहित (पॉइंटर्स द्वारा जुड़े हुए), सापेक्ष या निरपेक्ष, संकलन समय पर हल या गतिशील रूप से निर्मित हो सकते हैं। सभी परिस्थितियों के लिए कोई भी भिन्नता सर्वोत्तम नहीं है।

विकास

जगह बचाने के लिए, प्रोग्रामर्स ने सबरूटीन कॉल्स की सूचियों को सबरूटीन पतों की सरल सूचियों में निचोड़ा, और बदले में प्रत्येक सबरूटीन को कॉल करने के लिए एक छोटे लूप का उपयोग किया। उदाहरण के लिए, निम्नलिखित स्यूडोकोड दो संख्याओं A और B को जोड़ने के लिए इस तकनीक का उपयोग करता है। उदाहरण में, सूची को थ्रेड लेबल किया गया है और एक चर ip (निर्देश सूचक) सूची के भीतर हमारे स्थान को ट्रैक करता है। एक अन्य चर एसपी (स्टैक पॉइंटर) में मेमोरी में कहीं और पता होता है जो अस्थायी रूप से मान रखने के लिए उपलब्ध होता है।

start:
  ip = &thread  // points to the address '&pushA', not the textual label 'thread'
top:
  jump *ip++  // follow ip to address in thread, follow that address to subroutine, advance ip
thread:
  &pushA
  &pushB
  &add
  ...
pushA:
  *sp++ = A  // follow sp to available memory, store A there, advance sp to next 
  jump top
pushB:
  *sp++ = B
  jump top
add:
  addend1 = *--sp  // Pop the top value off the stack
  addend2 = *--sp  // Pop second value off the stack
  *sp++ = addend1 + addend2  // Add the two values together and store the result on the top of the stack
  jump top

कॉलिंग लूप at top इतना सरल है कि इसे प्रत्येक उपनेमका के अंत में इनलाइन दोहराया जा सकता है। नियंत्रण अब एक बार कूदता है, एक उपनेमका के अंत से दूसरे की प्रारंभ तक, दो बार कूदने के बजाय top. उदाहरण के लिए:

start:
  ip = &thread  // ip points to &pushA (which points to the first instruction of pushA)
  jump *ip++  // send control to first instruction of pushA and advance ip to &pushB
thread:
  &pushA
  &pushB
  &add
  ...
pushA:
  *sp++ = A  // follow sp to available memory, store A there, advance sp to next 
  jump *ip++  // send control where ip says to (i.e. to pushB) and advance ip
pushB:
  *sp++ = B
  jump *ip++
add:
  addend1 = *--sp  // Pop the top value off the stack
  addend2 = *--sp  // Pop second value off the stack
  *sp++ = addend1 + addend2  // Add the two values together and store the result on top of the stack
  jump *ip++

इसे डायरेक्ट थ्रेडेड कोड (डीटीसी) कहा जाता है। हालांकि तकनीक पुरानी है, थ्रेडेड कोड शब्द का पहला व्यापक रूप से परिचालित उपयोग संभवतः जेम्स आर. बेल का 1973 का लेख थ्रेडेड कोड है।[8] 1970 में, चार्ल्स एच. मूर ने अपनी फोर्थ वर्चुअल मशीन के लिए एक अधिक कॉम्पैक्ट व्यवस्था, अप्रत्यक्ष थ्रेडेड कोड (ITC) का आविष्कार किया। मूर इस व्यवस्था पर इसलिए पहुंचे क्योंकि डेटा जनरल नोवा मिनीकंप्यूटर के प्रत्येक एड्रैस में एक अप्रत्यक्ष बिट था, जिसने आईटीसी को आसान और तेज़ बना दिया। बाद में, उन्होंने कहा कि उन्हें यह इतना सुविधाजनक लगा कि उन्होंने बाद के सभी फोर्थ डिजाइनों में इसका प्रचार किया।[9] आज, कुछ फोर्थ कंपाइलर्स प्रत्यक्ष-थ्रेडेड कोड उत्पन्न करते हैं जबकि अन्य अप्रत्यक्ष-थ्रेडेड कोड उत्पन्न करते हैं। निष्पादक किसी भी तरह से कार्य करते हैं।

थ्रेडिंग मॉडल

व्यावहारिक रूप से सभी निष्पादन योग्य थ्रेडेड कोड सबरूटीन्स (प्रत्येक विधि को थ्रेडिंग मॉडल कहा जाता है) को लागू करने के लिए इन विधियों में से एक या दूसरे का उपयोग करता है।

डायरेक्ट थ्रेडिंग

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

स्टैक मशीन का एक उदाहरण अनुक्रम पुश ए, पुश बी, एड को निष्पादित कर सकता है। इसका अनुवाद निम्नलिखित थ्रेड और रूटीन में किया जा सकता है, जहाँ ip लेबल किए गए एड्रैस पर प्रारंभ किया गया है thread (यानी, पता जहां &pushA रखा है)।

#define PUSH(x) (*sp++ = (x))
#define POP() (*--sp)
start:
  ip = &thread  // ip points to &pushA (which points to the first instruction of pushA)
  jump *ip++  // send control to first instruction of pushA and advance ip to &pushB
thread:
  &pushA
  &pushB
  &add
  ...
pushA:
  PUSH(A)
  jump *ip++ // send control where ip says to (i.e. to pushB) and advance ip
pushB:
  PUSH(B)
  jump *ip++
add:
  result = POP() + POP()
  PUSH(result)
  jump *ip++

वैकल्पिक रूप से, ऑपरेंड को थ्रेड में सम्मिलित किया जा सकता है। यह उपरोक्त आवश्यक कुछ संकेतों को हटा सकता है, लेकिन धागे को बड़ा बनाता है:

#define PUSH(x) (*sp++ = (x))
#define POP() (*--sp)
start:
  ip = &thread
  jump *ip++
thread:
  &push
  &A  // address where A is stored, not literal A
  &push
  &B
  &add
  ...
push:
  variable_address = *ip++ // must move ip past operand address, since it is not a subroutine address
  PUSH(*variable_address) // Read value from variable and push on stack
  jump *ip++
add:
  result = POP() + POP()
  PUSH(result)
  jump *ip++

अप्रत्यक्ष थ्रेडिंग

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

उदाहरण के लिए, यदि लक्ष्य पुश ए, पुश बी, ऐड निष्पादित करना है, तो निम्न का उपयोग किया जा सकता है। यहाँ, ip पता करने के लिए प्रारंभ किया गया है &thread, प्रत्येक कोड खंड (push, add) के माध्यम से डबल-इनडायरेक्टिंग द्वारा पाया जाता है ip और एक अप्रत्यक्ष ब्लॉक; और फ़्रैगमेंट के किसी भी ऑपरेंड को फ़्रैगमेंट के एड्रैस के बाद अप्रत्यक्ष ब्लॉक में पाया जाता है। इसके लिए वर्तमान सबरूटीन को अंदर रखने की आवश्यकता है ip, पिछले सभी उदाहरणों के विपरीत जहां इसमें अगले सबरूटीन को बुलाया जाना था।

start:
  ip = &thread  // points to '&i_pushA'
  jump *(*ip)  // follow pointers to 1st instruction of 'push', DO NOT advance ip yet
thread:
  &i_pushA
  &i_pushB
  &i_add
  ...
i_pushA:
  &push
  &A
i_pushB:
  &push
  &B
i_add:
  &add
push:
  *sp++ = *(*ip + 1)  // look 1 past start of indirect block for operand address
  jump *(*++ip)  // advance ip in thread, jump through next indirect block to next subroutine
add:
  addend1 = *--sp
  addend2 = *--sp
  *sp++ = addend1 + addend2
  jump *(*++ip)

सबरूटीन थ्रेडिंग

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

Gforth कंपाइलर के सह-निर्माता एंटोन एर्टल ने कहा कि लोकप्रिय मिथकों के विपरीत, सबरूटीन थ्रेडिंग सामान्य रूप से डायरेक्ट थ्रेडिंग की तुलना में धीमी होती है।[10] हालाँकि, Ertl के सबसे हालिया परीक्षण[1]दिखाएँ कि 25 में से 15 परीक्षण मामलों में सबरूटीन थ्रेडिंग सीधे थ्रेडिंग से तेज़ है। अधिक विशेष रूप से, उन्होंने पाया कि डायरेक्ट थ्रेडिंग एक्सॉन, ओपर्टन और एथलॉन प्रोसेसर पर सबसे तेज़ थ्रेडिंग मॉडल है, पेंटियम एम प्रोसेसर पर अप्रत्यक्ष थ्रेडिंग सबसे तेज़ है, और सबरूटीन थ्रेडिंग पेंटियम 4, पेंटियम III और पीपीसी प्रोसेसर पर सबसे तेज़ है।

पुश A के लिए कॉल थ्रेडिंग के उदाहरण के रूप में, B को पुश करें, जोड़ें:

thread:
  call pushA
  call pushB
  call add
  ret
pushA:
  *sp++ = A
  ret
pushB:
  *sp++ = B
  ret
add:
  addend1 = *--sp
  addend2 = *--sp
  *sp++ = addend1 + addend2
  ret

टोकन थ्रेडिंग

टोकन-थ्रेडेड कोड संचालन की तालिका में सूचकांकों की सूची के रूप में थ्रेड को लागू करता है; घनत्व और दक्षता के लिए इंडेक्स चौड़ाई को स्वाभाविक रूप से जितना संभव हो उतना छोटा चुना जावा (प्रोग्रामिंग भाषा) में आसानी के लिए 1 बाइट / 8-बिट्स प्राकृतिक पसंद है, लेकिन 4-बिट्स जैसे छोटे आकार, या 12 या 16 बिट्स जैसे बड़े आकार का उपयोग समर्थित संचालन की संख्या के आधार पर किया जा सकता है। जब तक इंडेक्स की चौड़ाई को मशीन पॉइंटर की तुलना में संकरा चुना जाता है, तब तक यह प्रोग्रामर द्वारा विशेष प्रयास किए बिना स्वाभाविक रूप से अन्य थ्रेडिंग प्रकारों की तुलना में अधिक कॉम्पैक्ट होगा। यह सामान्य रूप से अन्य थ्रेडिंग के आकार का आधा से तीन-चौथाई होता है, जो स्वयं एक चौथाई से आठवें गैर-थ्रेडेड कोड के आकार का होता है। तालिका के संकेतक या तो अप्रत्यक्ष या प्रत्यक्ष हो सकते हैं। कुछ फोर्थ कंपाइलर्स टोकन-थ्रेडेड कोड उत्पन्न करते हैं। कुछ प्रोग्रामर पी-कोड मशीन | कुछ पास्कल (प्रोग्रामिंग भाषा) कंपाइलर्स द्वारा उत्पन्न पी-कोड, साथ ही साथ .NET Framework|.NET, Java (प्रोग्रामिंग लैंग्वेज), सामान्य संयुक्त प्रोग्रामिंग भाषा और कुछ C (प्रोग्रामिंग लैंग्वेज) द्वारा उपयोग किए जाने वाले बाईटकोड्स पर विचार करते हैं। संकलक, टोकन-थ्रेडिंग होना।

एक सामान्य दृष्टिकोण, ऐतिहासिक रूप से, बायटेकोड है, जो सामान्य रूप से स्टैक-आधारित वर्चुअल मशीन के साथ 8-बिट ऑपकोड का उपयोग करता है। मूलप्ररूपी बायटेकोड इंटरप्रेटर (कंप्यूटिंग) को डिकोड और डिस्पैच दुभाषिया के रूप में जाना जाता है और यह इस प्रकार है:

start:
  vpc = &thread
dispatch:
  addr = decode(&vpc) // Convert the next bytecode operation to a pointer to machine code that implements it
  // Any inter-instruction operations are performed here (e.g. updating global state, event processing, etc)
  jump addr
CODE_PTR decode(BYTE_CODE **p) {
  // In a more complex encoding, there may be multiple tables to choose between or control/mode flags
  return table[*(*p)++];
}
thread:  /* Contains bytecode, not machine addresses.  Hence it is more compact. */
  1 /*pushA*/
  2 /*pushB*/
  0 /*add*/
table:
  &add    /* table[0] = address of machine code that implements bytecode 0 */
  &pushA  /* table[1] ... */
  &pushB  /* table[2] ... */
pushA:
  *sp++ = A
  jump dispatch
pushB:
  *sp++ = B
  jump dispatch
add:
  addend1 = *--sp
  addend2 = *--sp
  *sp++ = addend1 + addend2
  jump dispatch

यदि वर्चुअल मशीन केवल बाइट-आकार के निर्देशों का उपयोग करती है, decode() बस से लाया गया है thread, लेकिन प्रायः सामान्य रूप से 1-बाइट निर्देशों का उपयोग किया जाता है और कुछ कम-सामान्य मल्टीबाइट निर्देश (जटिल निर्देश सेट कंप्यूटर देखें), जिस स्थिति में decode() अधिक जटिल है। एकल बाइट ऑपकोड का डिकोडिंग बहुत ही सरलता से और कुशलता से एक शाखा तालिका द्वारा सीधे एक इंडेक्स के रूप में ऑपकोड का उपयोग करके किया जा सकता है।

निर्देशों के लिए जहां व्यक्तिगत संचालन सरल होते हैं, जैसे कि पुश और ऐड, क्या निष्पादित करना है, यह तय करने में सम्मिलित कम्प्यूटेशनल ओवरहेड वास्तव में इसे निष्पादित करने की लागत से बड़ा है, इसलिए ऐसे दुभाषिए प्रायः मशीन कोड की तुलना में बहुत धीमे होते हैं। हालांकि, अधिक जटिल (यौगिक) निर्देशों के लिए, ओवरहेड प्रतिशत आनुपातिक रूप से कम महत्वपूर्ण है।

ऐसे समय होते हैं जब टोकन-थ्रेडेड कोड कभी-कभी समतुल्य मशीन कोड की तुलना में तेजी से चल सकता है जब वह मशीन कोड भौतिक सेंट्रल प्रोसेसिंग यूनिट के L1 निर्देश कैश में फ़िट होने के लिए बहुत बड़ा हो जाता है। थ्रेडेड कोड का उच्च कोड घनत्व, विशेष रूप से टोकन-थ्रेडेड कोड, इसे L1 कैश में पूरी तरह से फिट होने की अनुमति दे सकता है, जब यह अन्यथा नहीं होता, जिससे कैश थ्रैशिंग से बचा जा सकता है। हालाँकि, थ्रेडेड कोड निर्देश कैश (प्रत्येक ऑपरेशन के कार्यान्वयन के लिए) के साथ-साथ डेटा कैश (बायटेकोड और टेबल के लिए) दोनों का उपभोग करता है, मशीन कोड के विपरीत जो केवल निर्देश कैश का उपभोग करता है; इसका मतलब है कि थ्रेडेड कोड किसी भी समय सीपीयू द्वारा प्रसंस्करण के लिए रखे जा सकने वाले डेटा की मात्रा के लिए बजट में खाएगा। किसी भी मामले में, यदि गणना की जा रही समस्या में डेटा की एक छोटी मात्रा में बड़ी संख्या में ऑपरेशन लागू करना सम्मिलित है, तो थ्रेडेड कोड का उपयोग करना एक आदर्श अनुकूलन हो सकता है। [4]


हफ़मैन थ्रेडिंग

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

कम उपयोग की जाने वाली थ्रेडिंग

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

आरपीएल

Hewlett-Packard की RPL (प्रोग्रामिंग लैंग्वेज), जिसे पहली बार 1986 में HP-18C कैलकुलेटर में पेश किया गया था, एक प्रकार का मालिकाना हाइब्रिड डायरेक्ट-थ्रेडेड और इनडायरेक्ट-थ्रेडेड थ्रेडेड-इंटरप्रिटेड लैंग्वेज है, जो अन्य TILs के विपरीत, RPL ऑब्जेक्ट्स को एम्बेड करने की अनुमति देता है। रनस्ट्रीम यानी। पतों की धारा जिसके माध्यम से दुभाषिया सूचक आगे बढ़ता है। एक आरपीएल ऑब्जेक्ट को एक विशेष डेटा प्रकार के रूप में माना जा सकता है जिसकी इन-मेमोरी संरचना में ऑब्जेक्ट की प्रारंभ में ऑब्जेक्ट प्रोलॉग का पता होता है, और उसके बाद डेटा या निष्पादन योग्य कोड होता है। ऑब्जेक्ट प्रोलॉग निर्धारित करता है कि ऑब्जेक्ट के शरीर को कैसे निष्पादित या संसाधित किया जाना चाहिए। आरपीएल इनर लूप का उपयोग करना,[12] जिसका आविष्कार और प्रकाशन किया गया था (और पेटेंट कराया गया था [13]) 1986 में विलियम सी. विकेस द्वारा और प्रोग्रामिंग एनवायरनमेंट, इंस्टीट्यूट फॉर एप्लाइड फोर्थ रिसर्च, इंक., 1988 में प्रकाशित, निष्पादन इस प्रकार है:

  1. IP (निर्देश सूचक) को हटा दें और इसे O (वर्तमान ऑब्जेक्ट पॉइंटर) में संग्रहीत करें
  2. आईपी को एक एड्रेस पॉइंटर की लंबाई से बढ़ाएं
  3. Dereference O और इसके एड्रैस को O_1 में संग्रहीत करें (यह संकेत का दूसरा स्तर है)
  4. पीसी (प्रोग्राम काउंटर) को O_1 प्लस एक एड्रेस पॉइंटर पर सेट करके अगले पॉइंटर या एम्बेडेड ऑब्जेक्ट पर नियंत्रण स्थानांतरित करें
  5. चरण 1 पर वापस जाएं

यह अधिक सटीक रूप से प्रतिनिधित्व कर सकता है:

    O  = [I]
    I  = I + Δ
    PC = [O] + Δ

जहाँ ऊपर, O वर्तमान ऑब्जेक्ट पॉइंटर है, I इंटरप्रेटर पॉइंटर है, Δ एक एड्रेस शब्द की लंबाई है और [] ऑपरेटर dereference के लिए खड़ा है।

जब किसी ऑब्जेक्ट पॉइंटर या एम्बेडेड ऑब्जेक्ट पर नियंत्रण स्थानांतरित किया जाता है, तो निष्पादन निम्नानुसार जारी रहता है:

<पूर्व> PROLOG -> PROLOG (प्रोलॉग कोड की प्रारंभ में प्रोलॉग पता खुद को इंगित करता है)

   PROLOG -> PROLOG ( The prolog address at the start of the prolog code points to itself )
    IF O + Δ =/= PC
    THEN GOTO INDIRECT ( Test for direct execution )
        O = I - Δ ( Correct O to point to start of embedded object )
        I = I + α ( Correct I to point after embedded object where α is the length of the object )
    INDIRECT ( rest of prolog )

एचपी के एचपी शनि माइक्रोप्रोसेसरों पर जो आरपीएल का उपयोग करते हैं, एक वास्तुशिल्प/प्रोग्रामिंग ट्रिक द्वारा संभव बनाया गया एक तीसरा स्तर है जो तेजी से निष्पादन की अनुमति देता है।[12]


शाखाएँ

सभी दुभाषियों में, एक शाखा केवल थ्रेड पॉइंटर (ip) थ्रेड में किसी भिन्न एड्रैस पर। एक कंडीशनल जंप-इफ-जीरो ब्रांच जो केवल तभी जंप करती है जब टॉप-ऑफ-स्टैक वैल्यू शून्य हो, जैसा कि नीचे दिखाया गया है। यह उदाहरण डायरेक्ट थ्रेडिंग के एम्बेडेड पैरामीटर संस्करण का उपयोग करता है ताकि &thread[123] लाइन वह गंतव्य है जहां स्थिति सही होने पर कूदना है, इसलिए इसे छोड़ दिया जाना चाहिए (ip++) खत्म अगर शाखा नहीं ली जाती है।

thread:
  ...
  &brz
  &thread[123]
  ...
brz:
  when_true_ip = *ip++ // Get destination address for branch
  if (*--sp == 0)      // Pop/Consume top of stack and check if it's zero
    ip = when_true_ip
  jump *ip++

सामान्य सुविधाएं

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

थ्रेडेड वर्चुअल मशीन में प्रायः तीन प्रोसेसर रजिस्टर सम्मिलित होते हैं। सबरूटीन्स ('शब्द') के बीच डेटा पास करने के लिए एक और सम्मिलित है। ये:

  • वर्चुअल मशीन का आईपी या आई (निर्देश सूचक) (वीएम को लागू करने वाले अंतर्निहित हार्डवेयर के कार्यक्रम गणक के साथ भ्रमित नहीं होना चाहिए)
  • डब्ल्यू (कार्य सूचक)
  • आरपी या आर (रिटर्न स्टैक (डेटा स्ट्रक्चर) पॉइंटर)
  • एसपी या एस (शब्दों के बीच पैरामीटर पास करने के लिए पैरामीटर स्टैक पॉइंटर)

प्रायः, थ्रेडेड वर्चुअल मशीन, जैसे फोर्थ के कार्यान्वयन में, दिल में एक साधारण वर्चुअल मशीन होती है, जिसमें तीन आदिम होते हैं। वे हैं:

  1. घोंसला, जिसे डोकोल भी कहा जाता है
  2. unnest, या semi_s (;s)
  3. अगला

अप्रत्यक्ष-थ्रेडेड वर्चुअल मशीन में, यहाँ दिए गए ऑपरेशन हैं:

 next:
   *ip++ -> w
   jump **w++
 nest:
   ip -> *rp++
   w -> ip
   next
 unnest:
   *--rp -> ip
   next

यह भी देखें

टिप्पणियाँ

  1. Dartmouth BASIC, upon which Microsoft BASIC is ultimately based, was a compiler that ran on mainframe machines.


संदर्भ

  1. 1.0 1.1 "Speed of various interpreter dispatch techniques V2".
  2. Dennis M. Ritchie, "The Development of the C Language", 1993. Quote: "The B compiler on the PDP-7 did not generate machine instructions, but instead 'threaded code' ..."
  3. David Frech. "muforth readme". section "Simple and tail-recursive native compiler".
  4. 4.0 4.1 Steve Heller. "Efficient C/C++ Programming: Smaller, Faster, Better". 2014. Chapter 5: "Do you need an interpreter?" p. 195.
  5. Jean-Paul Tremblay; P. G. Sorenson. "The Theory and Practice of Compiler Writing". 1985. p. 527
  6. "Wireless World: Electronics, Radio, Television, Volume 89". p. 73.
  7. "Byte, Volume 5". 1980. p. 212
  8. Bell, James R. (1973). "Threaded code". Communications of the ACM. 16 (6): 370–372. doi:10.1145/362248.362270.
  9. Moore, Charles H., published remarks in Byte Magazine's Forth Issue
  10. Ertl, Anton. "What is Threaded Code?".
  11. Latendresse, Mario; Feeley, Marc. Generation of Fast Interpreters for Huffman-Compressed Bytecode. Elsevier. CiteSeerX 10.1.1.156.2546.
  12. 12.0 12.1 Busby, Jonathan. "The RPL inner loop explained", "The Museum of HP Calculators", 7 September 2018, Retrieved on 27 December 2019
  13. Wickes, William C. (May 30, 1986). "Data processing system and method for the direct and indirect execution of uniformly structured object types". uspto.gov. Retrieved December 27, 2019.


बाहरी संबंध