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

From Vigyanwiki
No edit summary
No edit summary
 
(3 intermediate revisions by 3 users not shown)
Line 2: Line 2:
''मल्टी-थ्रेडेड प्रोग्रामिंग या जंप थ्रेडिंग से भ्रमित न हों।''
''मल्टी-थ्रेडेड प्रोग्रामिंग या जंप थ्रेडिंग से भ्रमित न हों।''


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


थ्रेडेड कोड में वैकल्पिक पीढ़ी तकनीकों और वैकल्पिक कॉलिंग सम्मेलनों द्वारा उत्पन्न कोड की तुलना में बेहतर [[कोड घनत्व]] होता है। [[कैश (कंप्यूटिंग)]] आर्किटेक्चर में, यह [[निष्पादन (कंप्यूटिंग)]] थोड़ा धीमा हो सकता है।{{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> [[धागा स्विच]]िंग पर छोटे प्रोग्राम भी तेज़ हो सकते हैं, जब अन्य प्रोग्राम कैश भर चुके हों।
थ्रेडेड कोड में वैकल्पिक पीढ़ी(जनरेशन) तकनीकों और वैकल्पिक कॉलिंग कन्वेंशन द्वारा उत्पन्न कोड की तुलना में अपेक्षाकृत अधिक [[कोड घनत्व|कोड]] संघनता होती है। [[कैश (कंप्यूटिंग)]] संरचना में, यह [[निष्पादन (कंप्यूटिंग)]] कुछ मंद हो सकता है।{{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}}
कंप्यूटर प्रोग्राम बनाने का सामान्य तरीका मशीन कोड में स्रोत कोड (कुछ [[प्रतीकात्मक भाषा (प्रोग्रामिंग)]] में लिखा गया) का अनुवाद करने के लिए एक कंपाइलर का उपयोग करना है। परिणामी [[निष्पादन]] योग्य सामान्य रूप से तीव्र होता है लेकिन, क्योंकि यह [[कंप्यूटर हार्डवेयर]] प्लेटफ़ॉर्म के लिए विशिष्ट है, यह पोर्टेबल नहीं है। एक [[आभासी मशीन]] के लिए निर्देश सेट उत्पन्न करने और प्रत्येक हार्डवेयर प्लेटफॉर्म पर दुभाषिया (कंप्यूटिंग) का उपयोग करने के लिए एक अलग दृष्टिकोण है। दुभाषिया वर्चुअल मशीन वातावरण को तुरंत संचालित करता है और निर्देशों को निष्पादित करता है। इस प्रकार, केवल दुभाषिया को संकलित किया जाना चाहिए।
कंप्यूटर प्रोग्राम बनाने का सामान्य तरीका मशीन कोड में स्रोत कोड (कुछ [[प्रतीकात्मक भाषा (प्रोग्रामिंग)]] में लिखा गया) का अनुवाद करने के लिए एक कंपाइलर का उपयोग करना है। परिणामी [[निष्पादन]] योग्य सामान्य रूप से तेज़ होता है लेकिन, क्योंकि यह [[कंप्यूटर हार्डवेयर]] प्लेटफ़ॉर्म के लिए विशिष्ट है, यह पोर्टेबल नहीं है। एक [[आभासी मशीन]] के लिए निर्देश सेट उत्पन्न करने और प्रत्येक हार्डवेयर प्लेटफॉर्म पर दुभाषिया (कंप्यूटिंग) का उपयोग करने के लिए एक अलग दृष्टिकोण है। दुभाषिया वर्चुअल मशीन वातावरण को तुरंत चालू करता है और निर्देशों को निष्पादित करता है। इस प्रकार, केवल दुभाषिया को संकलित किया जाना चाहिए।


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


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


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


मेनफ्रेम और कुछ प्रारम्भिक माइक्रोप्रोसेसरों जैसे [[आरसीए 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>
David Frech.
David Frech.
[https://muforth.nimblemachines.com/readme/ "muforth readme"].
[https://muforth.nimblemachines.com/readme/ "muforth readme"].
Line 49: Line 48:
p. 212
p. 212
</ref>
</ref>
इन वर्षों में, प्रोग्रामर ने उस दुभाषिया या छोटे चयनकर्ता पर कई बदलाव किए हैं। पतों की सूची में विशेष पता एक इंडेक्स, [[सामान्य प्रयोजन रजिस्टर]] या [[सूचक (कंप्यूटर प्रोग्रामिंग)]] का उपयोग करके निकाला जा सकता है। एड्रैस प्रत्यक्ष या अप्रत्यक्ष, सन्निहित या गैर-सन्निहित (पॉइंटर्स द्वारा जुड़े हुए), सापेक्ष या निरपेक्ष, संकलन समय पर हल या गतिशील रूप से निर्मित हो सकते हैं। सभी परिस्थितियों के लिए कोई भी भिन्नता सर्वोत्तम नहीं है।
 
इन वर्षों में, प्रोग्रामर ने उस दुभाषिया या छोटे चयनकर्ता पर कई परिवर्तन किए हैं। एड्रैस की सूची में विशेष एड्रैस एक इंडेक्स, [[सामान्य प्रयोजन रजिस्टर]] या [[सूचक (कंप्यूटर प्रोग्रामिंग)|पॉइंटर (कंप्यूटर प्रोग्रामिंग)]] का उपयोग करके निकाला जा सकता है। एड्रैस प्रत्यक्ष या अप्रत्यक्ष, सन्निहित या गैर-सन्निहित (पॉइंटर्स द्वारा जुड़े हुए), सापेक्ष या निरपेक्ष, संकलन समय पर संशोधित या गतिशील रूप से निर्मित हो सकते हैं। सभी परिस्थितियों के लिए कोई भी भिन्नता सर्वोत्तम नहीं है।


== विकास ==
== विकास ==
जगह बचाने के लिए, प्रोग्रामर्स ने सबरूटीन कॉल्स की सूचियों को सबरूटीन पतों की सरल सूचियों में निचोड़ा, और बदले में प्रत्येक सबरूटीन को कॉल करने के लिए एक छोटे लूप का उपयोग किया। उदाहरण के लिए, निम्नलिखित स्यूडोकोड दो संख्याओं A और B को जोड़ने के लिए इस तकनीक का उपयोग करता है। उदाहरण में, सूची को थ्रेड लेबल किया गया है और एक चर ip (निर्देश सूचक) सूची के भीतर हमारे स्थान को ट्रैक करता है। एक अन्य चर एसपी (स्टैक पॉइंटर) में मेमोरी में कहीं और पता होता है जो अस्थायी रूप से मान रखने के लिए उपलब्ध होता है।
स्थान बचाने के लिए, प्रोग्रामर्स ने सबरूटीन कॉल्स की सूचियों को सबरूटीन एड्रैस की सामान्य सूचियों में निष्पीडित, और बदले में प्रत्येक सबरूटीन को कॉल करने के लिए एक छोटे लूप का उपयोग किया। उदाहरण के लिए, निम्नलिखित स्यूडोकोड दो संख्याओं A और B को जोड़ने के लिए इस तकनीक का उपयोग करता है। उदाहरण में, सूची को थ्रेड लेबल किया गया है और एक वेरिएबल आईपी (निर्देश पॉइंटर) सूची के अंदर हमारे स्थान को ट्रैक करता है। एक अन्य वेरिएबल एसपी (स्टैक पॉइंटर) में मेमोरी में कहीं और एड्रैस होता है जो अस्थायी रूप से मान रखने के लिए उपलब्ध होता है।
  start:
  start:
  ip = &thread // points to the address '&pushA', not the textual label 'thread'
  ip = &thread // points to the address '&pushA', not the textual label 'thread'
  top:
  top:
  jump *ip++ // follow ip to address in thread, follow that address to subroutine, advance ip
  jump *ip++ // follow ip to address in thread, follow that address to subroutine, advance ip
  thread:
  thread:
  &pushA
  &pushA
  &pushB
  &pushB
  &add
  &add
  ...
  ...
  pushA:
  pushA:
  *sp++ = A // follow sp to available memory, store A there, advance sp to next  
  *sp++ = A // follow sp to available memory, store A there, advance sp to next  
  jump top
  jump top
  pushB:
  pushB:
  *sp++ = B
  *sp++ = B
  jump top
  jump top
  add:
  add:
  addend1 = *--sp // Pop the top value off the stack
  addend1 = *--sp // Pop the top value off the stack
  addend2 = *--sp // Pop second 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
  *sp++ = addend1 + addend2 // Add the two values together and store the result on the top of the stack
  jump top
  jump top
कॉलिंग लूप at <code>top</code> इतना सरल है कि इसे प्रत्येक उपनेमका के अंत में इनलाइन दोहराया जा सकता है। नियंत्रण अब एक बार कूदता है, एक उपनेमका के अंत से दूसरे की प्रारंभ तक, दो बार कूदने के बजाय <code>top</code>. उदाहरण के लिए:
<code>top</code> पर कॉलिंग लूप इतना सामान्य है कि इसे प्रत्येक सबरूटीन के अंत में इनलाइन द्वारा पुनरावृत किया जा सकता है। <code>top</code>से होकर दो बार जंप के अतिरिक्त नियंत्रण सिर्फ एक सबरूटीन के अंत से दूसरे के प्रारंभ तक एक बार जंप है। उदाहरण के लिए:
  start:
  start:
  ip = &thread // ip points to &pushA (which points to the first instruction of pushA)
  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
  jump *ip++ // send control to first instruction of pushA and advance ip to &pushB
  thread:
  thread:
  &pushA
  &pushA
  &pushB
  &pushB
  &add
  &add
  ...
  ...
  pushA:
  pushA:
  *sp++ = A // follow sp to available memory, store A there, advance sp to next  
  *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
  jump *ip++ // send control where ip says to (i.e. to pushB) and advance ip
  pushB:
  pushB:
  *sp++ = B
  *sp++ = B
  jump *ip++
  jump *ip++
  add:
  add:
  addend1 = *--sp // Pop the top value off the stack
  addend1 = *--sp // Pop the top value off the stack
  addend2 = *--sp // Pop second 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
  *sp++ = addend1 + addend2 // Add the two values together and store the result on top of the stack
  jump *ip++
  jump *ip++
इसे डायरेक्ट थ्रेडेड कोड (डीटीसी) कहा जाता है। हालांकि तकनीक पुरानी है, थ्रेडेड कोड शब्द का पहला व्यापक रूप से परिचालित उपयोग संभवतः जेम्स आर. बेल का 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 में, चार्ल्स एच. मूर ने अपनी फोर्थ वर्चुअल मशीन के लिए एक अधिक कॉम्पैक्ट व्यवस्था, अप्रत्यक्ष थ्रेडेड कोड (आईटीसी) का आविष्कार किया। मूर इस व्यवस्था पर इसलिए पहुंचे क्योंकि डेटा जनरल नोवा मिनीकंप्यूटर के प्रत्येक एड्रैस में एक [[अप्रत्यक्ष बिट]] था, जिसने आईटीसी को आसान और तीव्र बना दिया। बाद में, उन्होंने कहा कि उन्हें यह इतना सुविधाजनक लगा कि उन्होंने बाद के सभी फोर्थ डिजाइनों में इसका प्रचार किया।<ref>Moore, Charles H., published remarks in Byte Magazine's Forth Issue</ref>
 
आज, कुछ फोर्थ कंपाइलर्स प्रत्यक्ष-थ्रेडेड कोड उत्पन्न करते हैं जबकि अन्य अप्रत्यक्ष-थ्रेडेड कोड उत्पन्न करते हैं। निष्पादक किसी भी तरह से कार्य करते हैं।
आज, कुछ फोर्थ कंपाइलर्स प्रत्यक्ष-थ्रेडेड कोड उत्पन्न करते हैं जबकि अन्य अप्रत्यक्ष-थ्रेडेड कोड उत्पन्न करते हैं। निष्पादक किसी भी तरह से कार्य करते हैं।


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


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


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


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