2008-12-11 10 views
10

मेरे पास एक परिदृश्य है जब मैं थ्रेडपूल के साथ 3.10 धागे शुरू करता हूं। प्रत्येक धागा अपनी नौकरी करता है और थ्रेडपूल पर लौटता है। सभी पृष्ठभूमि धागे समाप्त होने पर मुख्य धागे में अधिसूचित होने के संभावित विकल्प क्या हैं?अधिसूचित किया जाएगा जब सभी पृष्ठभूमि थ्रेडपूल धागे समाप्त हो जाते हैं

वर्तमान में मैं प्रत्येक निर्मित धागे के लिए एक चर बढ़ाने के साथ एक होमग्राउन विधि का उपयोग कर रहा हूं और पृष्ठभूमि थ्रेड खत्म होने पर इसे घटाना चाहता हूं। यह ठीक काम करता है, लेकिन अगर बेहतर विकल्प हैं तो मैं उत्सुक था।

उत्तर

11

Interlocked.Decrement के साथ किए जाने तक एक चर (धागे के बीच) को कम करना जोखिम भरा होता है, लेकिन यदि आपके पास अंतिम धागा है (यानी जब यह शून्य हो जाता है) एक ईवेंट उठाते हैं तो यह दृष्टिकोण ठीक होना चाहिए। ध्यान दें कि अपवादों के मामले में इसे खोने से बचने के लिए इसे "आखिरकार" ब्लॉक में होना होगा (साथ ही आप प्रक्रिया को मारना नहीं चाहते हैं)।

"समांतर एक्सटेंशन" (या .NET 4.0 के साथ) में, आप यहां Parallel.ForEach विकल्प भी देख सकते हैं ... जो कि ब्लॉक के रूप में सब कुछ करने का एक और तरीका हो सकता है। उन्हें मैन्युअल रूप से देखने के बिना।

+0

हाय मार्क। मैं इंटरलॉक या लॉक कीवर्ड के साथ इसे थ्रेड सुरक्षित तरीके से कर रहा हूं। यह ठीक काम करता है और एक गैर-अवरुद्ध तरीके से। मैं सोच रहा था कि ऐसा करने के लिए अंतर्निहित प्राइमेटिव हैं या नहीं। धन्यवाद। – Valentin

2

इस समय ऐसा करने का एक अंतर्निहित तरीका नहीं है - मुझे पूल धागे का उपयोग करने के बारे में सबसे बड़ी पीड़ा मिलती है।

जैसा कि मार्क कहते हैं, यह समान प्रकार की चीजें हैं जो समांतर एक्सटेंशन/.NET 4.0 में तय की जा रही हैं।

1

क्या आप प्रत्येक थ्रेड को एक अलग मैनुअल रीसेट इवेंट नहीं दे सकते थे और प्रत्येक ने ईवेंट को पूरा करते समय सेट किया था। फिर, मुख्य धागे में आप पारित सभी घटनाओं पर इंतजार कर सकते हैं।

0

मार्क का समाधान सबसे अच्छा है अगर आप जानना चाहते हैं कि सभी नौकरियां कब समाप्त हो चुकी हैं, और उससे बेहतर जानकारी की आवश्यकता नहीं है (जैसा कि लगता है आपका मामला बनें)।

यदि आप कुछ धागे नौकरी पैदा करने के लिए चाहते थे, और अधिसूचनाएं प्राप्त करने के लिए कुछ अन्य धागे, तो आप WaitHandle का उपयोग कर सकते हैं। कोड बहुत लंबा है।

int length = 10; 
    ManualResetEvent[] waits = new ManualResetEvent[length]; 
    for (int i = 0; i < length; i++) { 
     waits[i] = new ManualResetEvent(false); 
     ThreadPool.QueueUserWorkItem((obj) => { 
      try { 

      } finally { 
       waits[i].Set(); 
      } 
     }); 
    } 

    for (int i = 0; i < length; i++) { 
     if (!waits[i].WaitOne()) 
      break; 
    } 

WaitOne विधि, लिखित रूप में, हमेशा सच देता है, लेकिन मैं इसे इस तरह लिखा है तुम्हें याद है कि कुछ भार के एक तर्क के रूप में एक समय समाप्ति ले बनाने के लिए।

3

तो इसकी 64 से अधिक नहीं धागे पर प्रतीक्षा करने के लिए, तो आप इस तरह WaitHandle.WaitAll विधि का उपयोग कर सकते हैं:

List<WaitHandle> events = new List<WaitHandle>(); 
for (int i = 0; i < 64; i++) 
{ 
    ManualResetEvent mre = new ManualResetEvent(false); 
    ThreadPool.QueueUserWorkItem(
     delegate(object o) 
     { 
      Thread.Sleep(TimeSpan.FromMinutes(1)); 
      ((ManualResetEvent)o).Set(); 
     },mre); 
    events.Add(mre); 
} 
WaitHandle.WaitAll(events.ToArray()); 

निष्पादन इंतजार करेंगे जब तक सभी ManualResetEvents सेट कर रहे हैं, वैकल्पिक रूप से, आप WaitAny विधि का उपयोग कर सकते हैं ।

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

+1

यह विधि तब तक बढ़िया काम करती है जब तक मुख्य() एकल थ्रेड अपार्टमेंट नहीं है ([STAThread])। –

+0

"प्रतीक्षा करने के लिए 64 से अधिक थ्रेड" होने की आवश्यकता क्यों है? – jp2code

+0

वाह, वह प्रश्न हिट करता है ... उत्तर 4 साल से अधिक पुराना है ... जैसा कि मुझे याद है कि वेटहैंडल में एक सीमा है। अगर हम हैंडल की सूची में 64 से अधिक आइटम हैं तो एक अपवाद फेंकता है। शायद यह आज पुराना है। –

0

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

4

इस प्रयास करें: https://bitbucket.org/nevdelap/poolguard

using (var poolGuard = new PoolGuard()) 
{ 
    for (int i = 0; i < ... 
    { 
     ThreadPool.QueueUserWorkItem(ChildThread, poolGuard); 
    } 
    // Do stuff. 
    poolGuard.WaitOne(); 
    // Do stuff that required the child threads to have ended. 

void ChildThread(object state) 
{ 
    var poolGuard = state as PoolGuard; 
    if (poolGuard.TryEnter()) 
    { 
     try 
     { 
      // Do stuff. 
     } 
     finally 
     { 
      poolGuard.Exit(); 
     } 
    } 
} 

एकाधिक PoolGuards जब धागे समाप्त हो ट्रैक करने के लिए अलग अलग तरीकों से इस्तेमाल किया जा सकता है, और धागे कि शुरू नहीं किया है जब पूल पहले से ही बंद कर दिया है संभालती है।

+0

आलेख अब उपलब्ध नहीं है। पूलगार्ड कक्षा क्या है? क्या आप पूरा कोड कॉपी कर सकते हैं? – Niloofar

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