मैं इस अभ्यास का उपयोग कुछ शैक्षिक उपकरण के रूप में कर रहा हूं ताकि मुझे कुछ जावा जीयूआई प्रोग्रामिंग अवधारणाओं में जलने में मदद मिल सके। जो मैं खोज रहा हूं वह एक सामान्य समस्या है, एक विशिष्ट समस्या के विस्तृत समाधान के बजाय। मुझे उम्मीद है कि यह "सही" कोडिंग मुझे भविष्य में बहु-थ्रेडेड समस्याओं से संपर्क करने के बारे में बहुत कुछ सिखाएगा। यदि यह इस मंच के लिए बहुत सामान्य है, तो संभवतः यह प्रोग्रामर में है?मैं स्विंगवर्कर के साथ एक बफरर्ड परिधीय डिवाइस का अनुकरण कैसे करूं?
मैं एक कार्ड रीडर अनुकरण कर रहा हूं। इसमें एक जीयूआई है, जो हमें हॉपर में कार्ड लोड करने और स्टार्ट और बहुत आगे प्रेस करने की इजाजत देता है, लेकिन इसका मुख्य "क्लाइंट" सीपीयू है, जो अलग थ्रेड पर चल रहा है और कार्ड का अनुरोध करता है।
कार्ड रीडर एक एकल बफर बनाए रखता है। यदि कोई कार्ड अनुरोध आता है और बफर खाली होता है, तो कार्ड रीडर को हॉपर से कार्ड पढ़ना चाहिए (जो एक सेकंड का 1/4 लेता है, यह 1 9 62 है)। कार्ड को बफर में पढ़ने के बाद, कार्ड रीडर सीपीयू को बफर भेजता है, और अगले अनुरोध के पहले तुरंत एक और बफर लोडिंग ऑपरेशन शुरू करता है।
यदि न केवल बफर खाली है, लेकिन हॉपर में कोई कार्ड नहीं है, तो हमें तब तक इंतजार करना चाहिए जब तक ऑपरेटर ने हॉपर में एक डेक लगाया और दबाया स्टार्ट (जो हमेशा बफर-लोड ऑपरेशन शुरू करता है)।
मेरे कार्यान्वयन में, कार्ड रीडर को कार्ड रीडर को invokeLater()
Runnables
के रूप में ईडीटी पर कतारबद्ध किया गया है। myRunnable.run()
समय पर, या तो एक बफर उपलब्ध होगा (इस मामले में हम इसे सीपीयू को भेज सकते हैं और एक और बफर-लोड ऑपरेशन बंद कर सकते हैं), या बफर खाली हो जाएगा। क्या होगा यदि यह खाली है?
दो संभावनाएं: (ए) उड़ान में पहले से ही एक बफर लोड ऑपरेशन है, या (बी) कार्ड हॉपर खाली है (या शुरू नहीं हुआ है)। किसी भी मामले में, ईडीटी प्रतीक्षा रखने के लिए स्वीकार्य नहीं है। काम (और प्रतीक्षा) पृष्ठभूमि धागे पर किया जाना चाहिए।
सादगी के लिए, मैंने बफर की स्थिति के बावजूद प्रत्येक कार्ड अनुरोध के जवाब में एक स्विंगवर्कर को घुमाने की कोशिश की। स्यूडोकोड था:
SwingWorker worker = new SwingWorker<Void, Void>() {
public Void doInBackground() throws Exception {
if (buffer.isEmpty()) {
/*
* fill() takes 1/4 second (simulated by Thread.sleep)
* or possibly minutes if we need to have another
* card deck mounted by operator.
*/
buffer.fill();
}
Card card = buffer.get(); // empties buffer
/*
* Send card to CPU
*/
CPU.sendMessage(card); // <== (A) put card in msg queue
/*
* Possible race window here!!
*/
buffer.fill(); // <== (B) pre-fetch next card
return null;
}
};
worker.execute();
यह उत्पादित कुछ अजीब समय प्रभाव - कारण, मुझे लगता है, एक buffer.fill()
दौड़ इस प्रकार हो सकता है कि करने के लिए: अगर, (ए) और (बी) के बीच, सीपीयू कार्ड दिखाया गया, एक और के लिए एक अनुरोध भेजा, और एक और स्विंगवर्कर धागा अपनी ओर से पैदा हुआ था, तो बफर भरने की कोशिश कर रहे दो धागे हो सकते हैं। [प्री-फ़ेच कॉल को हटाकर (बी) को हल किया गया।]
तो मुझे लगता है कि प्रत्येक पढ़ने के लिए एक स्विंगवर्कर थ्रेड स्पॉइंग गलत है। कार्ड के बफरिंग और भेजने को एक थ्रेड में क्रमबद्ध किया जाना चाहिए। उस थ्रेड को बफर को प्री-फ़ेच करने का प्रयास करना चाहिए, और यदि हम कार्ड से बाहर निकलते हैं और हॉपर में और अधिक होने की प्रतीक्षा करनी है तो प्रतीक्षा और फिर से शुरू करने में सक्षम होना चाहिए। मुझे संदेह है कि स्विंगवर्कर के पास इसे संभालने के लिए एक लंबे समय से चलने वाले पृष्ठभूमि धागे होने की आवश्यकता है, लेकिन मैं अभी तक काफी कुछ नहीं हूं।
एक स्विंगवर्कर थ्रेड मानना एक तरीका है, मैं इसे कैसे कार्यान्वित कर सकता हूं, ईडीटी पर देरी को समाप्त कर सकता हूं, जिससे थ्रेड को हॉपर रीफिल का इंतजार करना बंद हो जाता है, और बफर भरने से पहले या बाद में पूरा होने की अनिश्चितता को संभालने की अनुमति मिलती है। कार्ड अनुरोध आता है?
संपादित करें: मैं another thread से एक जवाब मिला है और इसे यहाँ सारांश यह होगा: एक SwingWorker धागा उपयोग करने के बजाय
, यह सिफारिश की थी मैं एक बार एक ExecutorService
newSingleThreadExecutor()
बनाते हैं, शुरुआत में, और जीयूआई है यह execute(Runnable foo)
उपयोग करते हुए, इस प्रकार पर कतारबद्ध लंबा तरीकों (इस कोड EDT में चलता है):
private ExecutorService executorService;
::
/*
* In constructor: create the thread
*/
executorService = Executors.newSingleThreadExecutor();
::
/*
* When EDT receives a request for a card it calls readCard(),
* which queues the work out to the *single* thread.
*/
public void readCard() throws Exception {
executorService.execute(new Runnable() {
public void run() {
if (buffer.isEmpty()) {
/*
* fill() takes 1/4 second (simulated by Thread.sleep)
* or possibly minutes if we need to have another
* card deck mounted by operator.
*/
buffer.fill();
}
Card card = buffer.get(); // empties buffer
/*
* Send card to CPU
*/
CPU.sendMessage(card); // <== (A) put card in msg queue
/*
* No race! Next request will run on same thread, after us.
*/
buffer.fill(); // <== (B) pre-fetch next card
return;
}
});
}
इस और SwingWorker के बीच मुख्य अंतर यह है कि सिर्फ एक कार्यकर्ता धागा है सुनिश्चित करता है कि है।
पूछताछ की एक अलग लाइन से एक काम कर जवाब मिल गया है, और मेरा उत्तर संलग्न करने के लिए मूल प्रश्न संपादित:
यहाँ मेरी संशोधित समाधान है। (अगर यह एसओ-प्रोटोकॉल-सही नहीं है तो खुशी से बदल जाएगा!) – Chap