2010-03-26 16 views
13

मैं Threading from within a class with static and non-static methods पढ़ रहा था और मैं इसी तरह की स्थिति में हूं।स्टैटिक कोड एकाधिक धागे के साथ कैसे चलाता है?

मेरे पास एक स्थिर विधि है जो संसाधन से डेटा खींचती है और डेटा के आधार पर कुछ रनटाइम ऑब्जेक्ट बनाती है।

static class Worker{ 
    public static MyObject DoWork(string filename){ 
     MyObject mo = new MyObject(); 

     // ... does some work 

     return mo; 
    } 
} 

विधि थोड़ी देर लेती है (इस मामले में यह 5-10 एमबी फाइलें पढ़ रही है) और एक ऑब्जेक्ट देता है।

मैं इस विधि को लेना चाहता हूं और इसे एकाधिक थ्रेड स्थिति में उपयोग करना चाहता हूं ताकि मैं एक साथ कई फाइलें पढ़ सकूं। डिजाइन मुद्दों/दिशा-निर्देशों को अलग-अलग, एकाधिक थ्रेड इस कोड तक कैसे पहुंचेंगे?

चलो कहते हैं कि मैं कुछ इस तरह करते हैं ...

class ThreadedWorker { 
    public void Run() { 
     Thread t = new Thread(OnRun); 
     t.Start(); 
    } 

    void OnRun() { 
     MyObject mo = Worker.DoWork("somefilename"); 

     mo.WriteToConsole(); 
    } 
} 

समानांतर निष्पादन के लिए अनुमति देता है, प्रत्येक थ्रेड के लिए स्थिर विधि रन करता है?

+0

प्रतिक्रियाओं के लिए सभी को धन्यवाद, वे सभी शानदार रहे हैं! – Krisc

उत्तर

19

हां, विधि एकाधिक धागे में ठीक चलाने में सक्षम होना चाहिए। एकमात्र चीज जिसकी आपको चिंता करनी चाहिए, उसी फ़ाइल को एक ही समय में एकाधिक थ्रेड में एक्सेस करना है।

3

यदि स्थैतिक विधि धागे को सुरक्षित रखने के लिए लिखा गया है, तो इसे किसी थ्रेड से भी बुलाया जा सकता है या यहां तक ​​कि थ्रेड पूल में भी भेजा जा सकता है।

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

8

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

+1

स्थानीय चर की प्रतिलिपि, हां। विधि की प्रति, नहीं, लेकिन यह वास्तव में कोई फर्क नहीं पड़ता क्योंकि एकाधिक धागे बिना किसी समस्या के स्मृति के समान ब्लॉक को पढ़ सकते हैं। –

+0

@ फ़्रेड्रिक मोर्क आपका उत्तर वाकई अच्छा है। मेरा एक सवाल है। यदि मान लीजिए कि स्थैतिक विधि स्थैतिक वर्ग में है तो विधि के लिए प्रत्येक कॉल कक्षा की प्रतिलिपि भी बनायेगी, इसका मतलब है कि इसमें सभी स्थैतिक तरीकों की प्रतिलिपि या केवल यह एक स्थिर विधि है। –

1

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

चूंकि आपका कार्य स्थैतिक है, इसलिए आप सदस्य चर का उपयोग नहीं कर सकते हैं, जो इसे पुन: प्रवेश करने का एक तरीका नहीं होगा। यदि आपके पास एक स्थिर स्थानीय चर था जो राज्य को बनाए रखता था, तो यह फिर से प्रवेश करने का एक और तरीका नहीं होगा।

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

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

2

एक बात जब स्थिर तरीकों को क्रियान्वित आप ध्यान में रखना चाहिए समवर्ती स्थिर क्षेत्रों, जो केवल एक बार अस्तित्व में हैं। इसलिए, यदि विधि स्थैतिक फ़ील्ड पढ़ती है और लिखती है, तो सहमति समस्याएं हो सकती हैं।

हालांकि, वहाँ एक विशेषता ThreadStaticAttribute कहा जाता है जो कहते हैं एक अलग क्षेत्र है कि वहाँ प्रत्येक थ्रेड के लिए है। यह कुछ विशेष परिदृश्यों में सहायक हो सकता है।

स्थानीय चर प्रत्येक थ्रेड के लिए separte हैं, तो आप इस के बारे में परवाह करने की जरूरत नहीं। लेकिन फाइलों जैसे बाहरी संसाधनों से अवगत रहें, जो समवर्ती रूप से उपयोग किए जाने पर समस्याग्रस्त हो सकते हैं।

शुभकामनाओं सहित,
ओलिवर Hanappi

2

कोड पहलू है, जो पहले से ही उत्तर दिया गया है के अलावा, आप भी फ़ाइल तक पहुँचने की आई/ओ पहलू पर विचार करने की जरूरत है।

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

मैन्युअल रीसेट इवेंट फ़ील्ड सेट करें, इसे सक्रिय करें रीडर या कुछ इसी तरह से कॉल करें, यह और अधिक स्पष्ट हो जाएगा। इसे गलत के रूप में शुरू करें।

एक बूलियन फ़ील्ड सेट करें, इसे टर्मिनेट रीडर थ्रेड कहें। इसे झूठी के रूप में शुरू करें, फिर यह और अधिक स्पष्ट हो जाएगा।

एक कतार < स्ट्रिंग > फ़ील्ड सेट करें, इसे फ़ाइलें कॉल करें और इसे प्रारंभ करें।

मेरा मुख्य आवेदन धागा जांच करता है कि वहाँ इसे में प्रासंगिक फ़ाइल रास्तों में से प्रत्येक लिखने से पहले फ़ाइलों कतार पर एक ताला है देखने के लिए। एक बार फ़ाइल लिखी जाने के बाद, रीसेट ईवेंट कतार में पाठक थ्रेड को इंगित करता है कि कतार में अपठित फ़ाइलें हैं।

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

कार्यकर्ता थ्रेड का प्रत्येक उदाहरण फ़ाइल पर एक विशेष लॉक प्राप्त करने का प्रयास करता है, जब तक लॉक सफल होता है, तब तक यह समय-समय पर समाप्त हो जाता है, अगर यह असफल होता है, तो यह फ़ाइल को संसाधित करता है, यह या तो आवश्यकतानुसार पुनः प्रयास करता है, फेंकता है एक अपवाद और खुद को समाप्त कर देता है। अपवाद की स्थिति में, धागा कतार के अंत में फ़ाइल जोड़ सकता है ताकि एक और धागा इसे बाद में एक बार फिर से उठा सके। ध्यान रखें कि यदि आप ऐसा करते हैं, तो आपको अंतहीन पाश पर विचार करने की आवश्यकता है I/O पढ़ने के मुद्दे का कारण हो सकता है। इस तरह की घटना में असफल फाइलों का एक शब्दकोश काउंटर के साथ कितनी बार विफल रहा है, यह उपयोगी हो सकता है ताकि अगर कुछ सीमा तक पहुंची तो आप कतार के अंत में फ़ाइल को फिर से जोड़ना बंद कर सकते हैं।

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

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