18

मैं के लिए ट्रांसफार्मर के विकास कर रहा हूँ जावा 6 * 1) कि आंशिक मूल्यांकन का एक प्रकार प्रदर्शन करती है लेकिन सादगी के लिए विचार करते हैं, करते हैं, सार-वाक्य रचना-पेड़ एक जावा प्रोग्राम की व्याख्याjava.lang अनुकरण करने का सबसे अच्छा तरीका क्या है। पढ़ा?

किसी व्याख्या किए गए प्रोग्राम द्वारा Thread के व्यवहार को अनुकरण कैसे करें?

AstInterpreterjava.lang.Runnable को लागू करना चाहिए:

पल मैं मन में है निम्नलिखित पर

। यह भी java.lang.Thread (या इसके उप-वर्ग) के हर नए उदाहरण अभिव्यक्ति को फिर से लिखने चाहिए नई AstInterpreter उदाहरण के साथ Thread के लक्ष्य (java.lang.Runnable) की जगह:

संपादित करें: और अधिक जटिल उदाहरण प्रदान की है।

संपादित करें 2: टिप्पणी 1.

लक्ष्य कार्यक्रम:

class PrintDemo { 
    public void printCount(){ 
    try { 
     for(int i = 5; i > 0; i--) { 
      System.out.println("Counter --- " + i); 
     } 
    } catch (Exception e) { 
     System.out.println("Thread interrupted."); 
    } 
    } 
} 

class ThreadDemo extends Thread { 
    private Thread t; 
    private String threadName; 
    PrintDemo PD; 

    ThreadDemo(String name, PrintDemo pd){ 
     threadName = name; 
     PD = pd; 
    } 
    public void run() { 
    synchronized(PD) { 
     PD.printCount(); 
    } 
    System.out.println("Thread " + threadName + " exiting."); 
    } 

    public void start() 
    { 
     System.out.println("Starting " + threadName); 
     if (t == null) 
     { 
     t = new Thread (this, threadName); 
     t.start(); 
     } 
    } 
} 

public class TestThread { 
    public static void main(String args[]) { 
     PrintDemo PD = new PrintDemo(); 

     ThreadDemo T1 = new ThreadDemo("Thread - 1 ", PD); 
     ThreadDemo T2 = new ThreadDemo("Thread - 2 ", PD); 

     T1.start(); 
     T2.start(); 

     // wait for threads to end 
     try { 
     T1.join(); 
     T2.join(); 
     } catch(Exception e) { 
     System.out.println("Interrupted"); 
     } 
    } 
} 

कार्यक्रम 1 (ThreadTest - बाईटकोड व्याख्या):

new Thread(new Runnable() { 
    public void run(){ 
     ThreadTest.main(new String[0]); 
    } 
}); 

कार्यक्रम 2 (ThreadTest - एएसटी व्याख्या की):

final com.sun.source.tree.Tree tree = parse("ThreadTest.java"); 

new Thread(new AstInterpreter() { 
    public void run(){ 
     interpret(tree); 
    } 

    public void interpret(com.sun.source.tree.Tree javaExpression){ 
    //... 

    } 
}); 

परिणामस्वरूप प्रोग्राम 2 शुरुआती प्रोग्राम 1 के थ्रेड के व्यवहार को अनुकरण करता है?

1) वर्तमान में, source=8/target=8 योजना स्वीकार की गई है।

+1

हां, आप अपनी खुद की कक्षा लिख ​​सकते हैं जो रननेबल लागू करता है और वह रननेबल क्लास थ्रेड के अंदर चलाया जा सकता है।मैं यह देखने में असफल रहा कि आपकी AstInterpreter कक्षा क्या करती है कि एक नया रननेबल नहीं कर सकता है। –

+0

आप जावा 6 पर क्यों चल रहे हैं? कोई कारण नहीं है। जावा 7 और 8 पर आपके सभी "जावा 6" कोड चलाए जाएंगे, – SnakeDoc

+0

मैं वास्तव में जावा 6 के तहत चल रहा हूं। मैंने जावा 6 फीचर्स द्वारा ट्रांसफॉर्मर सीमित कर दिया है और इस प्रकार लैंग्टोल्स एपीआई के कारण एसडीके 6 का उपयोग करने के लिए मजबूर किया है। –

उत्तर

9

मुझे दो विकल्प दिखाई देते हैं:

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

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

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

+1

विशेष रूप से, निष्पादन के किसी प्रकार के अंतःक्रिया के बिना, आपने * आपके दुभाषिया में "रननेबल" मॉडल नहीं किए हैं। Sergej सही है। –

2

आप वास्तविक मूल्यों के साथ गणना करने वाले क्लासिक दुभाषिया का उपयोग करके आंशिक मूल्यांकन नहीं कर सकते हैं। आपको प्रतीकात्मक मूल्यों की आवश्यकता है।

आंशिक मूल्यांकन के लिए, आप जो चाहते हैं वह प्रत्येक प्रोग्राम बिंदु पर प्रतीकात्मक प्रोग्राम स्थिति की गणना करना है, और उसके बाद उस प्रोग्राम बिंदु पर ज्ञात राज्य के आधार पर कार्यक्रम बिंदु को सरल बनाना है। कार्यक्रम शुरू होने पर आप राज्य के बारे में जो कुछ जानते हैं उसे लिखकर आप अपनी आंशिक मूल्यांकन प्रक्रिया शुरू करते हैं।

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

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

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

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

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

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

यह सब व्यवस्थित करना आसान नहीं है, और यह संभवतः चलाने के लिए बहुत महंगा समय/स्पेसवाइड है। इस सब को बहुत श्रमिकों का एक उदाहरण तैयार करने की कोशिश कर रहा है, इसलिए मैं इसे यहां नहीं करूँगा।

मॉडल चेकर्स https://en.wikipedia.org/wiki/Model_checking "राज्य स्थान" उत्पन्न करने के मामले में एक बहुत ही समान बात करते हैं, और समान समय/स्थान परेशानी होती है। यदि आप राज्य को प्रबंधित करने के तरीके के बारे में अधिक जानना चाहते हैं, तो मैं इस पर साहित्य पढ़ूंगा।

+0

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

+0

सार व्याख्या: ठीक है, तो आप * एक प्रकार का प्रतीकात्मक अनुकरण, अच्छा उपयोग कर रहे हैं। आपको किसी भी नियंत्रण पथ के साथ ऐसा करने में सक्षम होना चाहिए, इसलिए शेष उत्तर लागू होता है। लेकिन यह स्पष्ट होना चाहिए कि जावा दुभाषिया का उपयोग स्वयं कांटा (यूके का विकल्प 1) पर नहीं करेगा। मेरा जवाब धागे के विकल्प (2) थ्रेड के अंतराल को अनुकरण करने पर जोर देने के साथ Sergej के विकल्प 2 पर एक अभिवादन है। –

+0

अगर मैं गलत हूं तो मुझे सही करें: ऐसा लगता है कि ReentrantLock के उप-वर्ग का उपयोग करके, अधिग्रहण थ्रेड की जानकारी रिकॉर्डिंग, थ्रेड सिमुलेशन में बहुत कम (या यहां तक ​​कि समाप्त) को कम करता है। मैं मानक लॉक को मेरा एक (ऊपर उल्लिखित दोनों) के साथ प्रतिस्थापित करता हूं और अपने लॉक क्लास के लॉक()/अनलॉक() के साथ 'सिंक्रनाइज़ किए गए' कथन को प्रतिस्थापित करता हूं। तो, संभवतः मेरे पास अतिरिक्त प्रयास किए बिना धागे हस्तक्षेप के बारे में पर्याप्त जानकारी होगी। –

संबंधित मुद्दे