2010-08-06 7 views
5

मैं एक विंडोज सेवा लिख ​​रहा हूं जो ThreadPool.QueueUserWorkItem() का उपयोग करता है। प्रत्येक धागा एक अल्पकालिक कार्य है।मैं थ्रेडपूल कैसे पूरा कर सकता हूं। जॉइन?

जब सेवा बंद हो जाती है, तो मुझे यह सुनिश्चित करना होगा कि वर्तमान में सभी थ्रेड जो पूर्ण हो रहे हैं। क्या कतार स्वयं को साफ़ होने तक प्रतीक्षा करने का कोई तरीका है?

उत्तर

8

आप प्रत्येक थ्रेड में एक ईवेंट (उदा। ManualResetEvent) बना सकते हैं, और इसे सिंक्रनाइज़ सूची में रख सकते हैं (lock निर्माण का उपयोग करके)। कार्य समाप्त होने पर ईवेंट को सेट करें या सूची से हटा दें।

जब आप शामिल होना चाहते हैं, तो आप सभी घटनाओं को संकेतित करने के लिए WaitHandle.WaitAll (MSDN documentation) का उपयोग कर सकते हैं।

यह एक हैक है, लेकिन मैं इसे किसी भी चीज़ को कम करने के तरीके को नहीं देख सकता!


संपादित करें: इसके अतिरिक्त, आप यह सुनिश्चित कर सकते हैं कि कोई भी नई घटना पोस्ट न हो, फिर कुछ सेकंड प्रतीक्षा करें। यदि वे वास्तव में अल्पकालिक हैं, तो आपको कोई समस्या नहीं होगी। यहां तक ​​कि सरल, लेकिन अधिक हैकी।

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

+0

उन्हें अल्पकालिक होना चाहिए, लेकिन मेरे उपयोग के मामले में, मुझे "काम करना चाहिए" से अधिक आश्वासन चाहिए। मैं पूल में धागे की संख्या को ट्रैक करने के लिए एक इंटरलॉक थ्रेड काउंटर का उपयोग करने के बारे में सोच रहा हूं, और उस बराबर शून्य पर प्रतीक्षा कर रहा हूं। – recursive

+0

दरअसल, मुझे काउंटर की तुलना में आपका पहला सुझाव बेहतर लगता है। – recursive

3

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

// Initialize to 1 because we are going to treat the current thread as 
// a work item as well. This is to avoid a race that could occur when 
// one work item gets queued and completed before the next work item 
// is queued. 
int count = 1; 
var finished = new ManualResetEvent(false); 
try 
{ 
    while (...) 
    { 
    Interlocked.Increment(ref counter); 
    ThreadPool.QueueUserWorkItem( 
     delegate(object state) 
     { 
     try 
     { 
      // Your task goes here. 
     } 
     finally 
     { 
      // Decrement the counter to indicate the work item is done. 
      if (Interlocked.Decrement(ref count) == 0) 
      { 
      finished.Set(); 
      } 
     } 
     }); 
    } 
} 
finally 
{ 
    // Decrement the counter to indicate the queueing thread is done. 
    if (Interlocked.Decrement(ref count) == 0) 
    { 
    finished.Set(); 
    } 
} 
finished.WaitOne();