2010-02-02 9 views
9
for (do it a bunch of times) 
{   
    while (backgroundWorker1.IsBusy && backgroundWorker2.IsBusy && 
      backgroundWorker3.IsBusy && backgroundWorker4.IsBusy && 
      backgroundWorker5.IsBusy) 
    { 
     System.Threading.Thread.Sleep(0001); 
    } 

    if (!backgroundWorker1.IsBusy) 
    { 
     backgroundWorker1.RunWorkerAsync(); 
    } 
    else if (!backgroundWorker2.IsBusy) 
    { 
     backgroundWorker2.RunWorkerAsync(); 
    } 
    else if (!backgroundWorker3.IsBusy) 
    { 
     backgroundWorker3.RunWorkerAsync(); 
    } 
    else if (!backgroundWorker4.IsBusy) 
    { 
     backgroundWorker4.RunWorkerAsync(); 
    } 
    else if (!backgroundWorker5.IsBusy) 
    { 
     backgroundWorker5.RunWorkerAsync(); 
    } 
} 

यह पांच बार (प्रत्येक बीजी-कार्यकर्ता एक बार) चलाता है और थोड़ी देर में अटक जाता है। पृष्ठभूमिकर्मी कभी व्यस्त होने से नहीं रोकते हैं? मैं उपलब्धता की जांच कैसे करूं?पृष्ठभूमिवर्कर्स व्यस्त होने से कभी नहीं रोकते

नोट: 5 कार्यकर्ता धागे हैं, यह आश्वस्त करता है कि उनमें से कोई भी कभी भी रोका नहीं जाता है, हमेशा उन्हें कार्य सौंपा जाता है। लेकिन वे मुझे बताने की जब वे उपलब्ध हैं, मैंने सोचा था कि एक सरल उपाय होता मना ..

- [संपादित करें अनुरोध] ---

वास्तव में यह केवल एक डमी पैरामीटर किया गया था, मैं इसे हटा दिया और यह बाहर निकलने के लिए भूल गया, मैं सिर्फ इसका इस्तेमाल dowork, जो गंदा काम करता है कॉल करने के लिए:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) 
{ 
    timeconsumingfunction(publicstring); 
} 

और timeconsumingfunction अंत करता है। डीबगर और लाइन प्रति लाइन चलने में इसमें कदम उठाना, यह अंत तक चला जाता है और अंतिम '}' में आता है। इसका मतलब है कि यह समाप्त होता है, है ना?

--- [संपादित करें उत्तर] ---- यह सिर्फ मुझे लगता है कि यह पृष्ठभूमि चल पाएंगे

Application.DoEvents(); 

के साथ लाइन

System.Threading.Thread.Sleep(0001); 

की जगह काम किया, लेकिन प्राप्त नहीं उत्तर दें और IsBusy टैग अपडेट न करें।

धन्यवाद सभी, महान उत्तरों, बहुत मदद की!

+0

यह निर्धारित करने का सबसे आसान तरीका है कि नौकरी समाप्त हो गई है, रनवॉर्कर पूर्ण घटना पर ब्रेकपॉइंट छोड़ना और कार्यक्रम चलाने देना है। यदि आप ब्रेकपॉइंट हिट करते हैं तो पृष्ठभूमि कार्यकर्ता ने नौकरी समाप्त कर दी है। – 53an

उत्तर

34

आपका पाश डेडलॉक पैदा कर रहा है, बीजीडब्ल्यू पूरा नहीं हो सकता है। समस्या RunWorker पूर्ण घटना है, यह UI थ्रेड पर उठाया गया है। बीजीडब्लू जादू के उस बिट को यूआई थ्रेड निष्क्रिय होने की आवश्यकता है, इसे अपना संदेश लूप पंप करना होगा। समस्या यह है कि यूआई थ्रेड निष्क्रिय नहीं है और यह संदेश पंप नहीं कर रहा है, यह लूप के लिए फंस गया है। इस प्रकार, ईवेंट हैंडलर नहीं चल सकता है और IsBusy सच रहता है।

आपको इसे अलग-अलग करने की आवश्यकता होगी। RunWorker पूर्ण घटना का लाभ उठाने के लिए उस कोड को चलाने के लिए जिसे आप आमतौर पर लूप के लिए चलाएंगे। लूप के अंदर आवेदन। DoEvents() को कॉल करने के लिए सभी प्रलोभन का विरोध करें।

+0

यह लगभग एक शाश्वत की तरह है, और इसके बाद कुछ भी नहीं चलता है। मैं एक सरणी में (वेबसाइट के सूचकांक का उपयोग करके) वेबसाइट की उपलब्धता की जांच कर रहा हूं, इसलिए RunWorker में "जारी रखने" का कोई तरीका नहीं है। अगर आपको कोई परेशानी है, तो कृपया अपना जवाब संपादित करें .. मैं अनजान हूं :( – Marcelo

+0

और यह पूरा हो गया है। मैंने डीबगर के साथ इसका पालन किया है, और यह किसी दिए गए बिंदु पर "}" पर आता है कुछ नींद (0001) जो रनटाइम जितनी ज्यादा नहीं है, क्योंकि इसमें कदम के बीच समय है, इसलिए मैं लगभग 20 बार सोता हूं ... फिर यह फिर से चलता है, '}' तक जाता है, लेकिन उसके बाद भी DoWork का अंतिम "}", बीजीडब्ल्यू isBusy को झूठी में नहीं बदलेगा। – Marcelo

+3

नहीं, यह तब तक पूरा नहीं हुआ जब तक RunWorker पूर्ण ईवेंट समाप्त नहीं हो जाता है। DoWork ईवेंट हैंडलर पूरा होने के बाद कौन सा होता है। आरडब्ल्यूसी हैंडलर समस्या है , यह नहीं चल सकता है क्योंकि आपका यूआई थ्रेड लूप में फंस गया है। हैंडलर को हटा देना एक त्वरित फिक्स होगा। –

0

आईएसबीसी केवल इंगित करता है कि पृष्ठभूमि कार्यकर्ता वास्तव में एक ऑपरेशन कर रहा है। यह "कुछ" पूरा होने तक व्यस्त रहेगा। ऐसा लगता है कि "कुछ" खत्म नहीं होता है, जिससे आपके बैकग्राउंडर्स व्यस्त रहते हैं।

तो अगर आप "कुछ" क्या है, और संभवतः मुख्य धागे पर "कुछ" करने में कितना समय लगता है, तो यह मदद करेगा।

3

मेरा सुझाव है कि आप RunWorkerCompleted ईवेंट को संभालने के लिए अपना कोड बदल दें, जब आपके BackgroundWorker एस उनके काम के साथ समाप्त हो जाएंगे। में BackgroundWorker का उपयोग करने का एक उदाहरण है।

2

पृष्ठभूमि कार्यकर्ताओं का उपयोग करते समय मुझे भी यही समस्या थी और यह निष्कर्ष आया कि यदि आप एक लूप के भीतर नींद() का उपयोग करते हैं, तो यह अटक जाएगा। आप या तो RunWorker पूर्ण घटना का उपयोग कर सकते हैं और प्रत्येक कार्यकर्ता समाप्त होने पर इंगित करने के लिए एक बूलियन ध्वज सेट कर सकते हैं।

या यदि आप थ्रेड को रोकना चाहते हैं, तो आप पृष्ठभूमि श्रमिकों के बजाय थ्रेड का उपयोग करके देख सकते हैं। हालांकि तब पृष्ठभूमि कार्यकर्ता द्वारा प्रदान की जाने वाली घटनाओं के संबंध में आप आसानी से उपयोग खो देते हैं।

+0

उरग - हाँ, आलसी मत बनो - नींद() बस मुझे थोड़ा भी –

1

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

यदि आप विंडोज संदेशों को पंप नहीं करते हैं, तो आपके पृष्ठभूमि कार्यकर्ता की "पूर्ण" अधिसूचनाओं को संसाधित नहीं किया जाएगा, इसलिए स्थिति व्यस्त रहेगी।

0

समस्या यह है कि आप जो कुछ भी कर रहे हैं worker.RunWorkerAsync() कभी खत्म नहीं हो जाता है। शायद कुछ अंतहीन पाश या कुछ ऐसा है जो आपके DoWork ईवेंट में परिभाषित किया गया है।

यहाँ एक काम कर उदाहरण है, कि अगले मुक्त कार्यकर्ता का चयन करता है:

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Threading; 

namespace ConsoleApplication1 
{ 
    class Program 
    { 
     private static List<MyWorker> _Workers; 

     static void Main(string[] args) 
     { 
      _Workers = new List<MyWorker>(); 

      for (int i = 0; i < 5; i++) 
      { 
       _Workers.Add(CreateDefaultWorker(i)); 
      } 

      StartJobs(20000); 
      Console.ReadKey(); 
     } 

     private static void StartJobs(int runtime) 
     { 
      Random rand = new Random(); 
      DateTime startTime = DateTime.Now; 

      while (DateTime.Now - startTime < TimeSpan.FromMilliseconds(runtime)) 
      { 
       var freeWorker = GetFreeWorker(); 

       if (freeWorker != null) 
       { 
        freeWorker.Worker.RunWorkerAsync(new Action(() => DoSomething(freeWorker.Index, rand.Next(500, 2000)))); 
       } 
       else 
       { 
        Console.WriteLine("No free worker available!"); 
        Console.WriteLine("Waiting for free one..."); 
        WaitForFreeOne(); 
       } 
      } 
     } 

     private static MyWorker GetFreeWorker() 
     { 
      foreach (var worker in _Workers) 
      { 
       if (!worker.Worker.IsBusy) 
        return worker; 
      } 

      return null; 
     } 

     private static void WaitForFreeOne() 
     { 
      while (true) 
      { 
       foreach (var worker in _Workers) 
       { 
        if (!worker.Worker.IsBusy) 
         return; 
       } 
       Thread.Sleep(1); 
      } 
     } 

     private static MyWorker CreateDefaultWorker(int index) 
     { 
      var worker = new MyWorker(index); 

      worker.Worker.DoWork += (sender, e) => ((Action)e.Argument).Invoke(); 
      worker.Worker.RunWorkerCompleted += (sender, e) => Console.WriteLine("Job finished in worker " + worker.Index); 

      return worker; 
     } 

     static void DoSomething(int index, int timeout) 
     { 
      Console.WriteLine("Worker {1} starts to work for {0} ms", timeout, index); 
      Thread.Sleep(timeout); 
     } 
    } 

    public class MyWorker 
    { 
     public int Index { get; private set; } 
     public BackgroundWorker Worker { get; private set; } 

     public MyWorker(int index) 
     { 
      Index = index; 
      Worker = new BackgroundWorker(); 
     } 
    } 
} 
1

मैं एक ऐसी ही समस्या थी, और मैं क्या हल करने के लिए यह एक try... catch... and finally... बयान के साथ मुख्य कार्य संलग्न करने की था।

-1

आपकी समस्या के लिए एक कार्य समाधान नीचे दिए गए उदाहरण में दिया गया है। हंस पासेंट की तरह आपके कोड को पृष्ठभूमि कार्यकर्ता में दिखाया गया है लेकिन RunWorker प्रत्येक थ्रेड के पूर्ण होने पर केवल यूई थ्रेड में मूल्यांकन किया जाता है। ऐसा करने के लिए आप धागे, थ्रेडपूल की यूआई कतार में अपने अनुरोध को एनक्यू कर सकते हैं। इस प्रकार यूआई RunWorkerCompletedEvent का मूल्यांकन करता है और उसके बाद आपके कोड पर वापस कूद जाता है।

for (int i = 0; i < 999999; ++i) 
{ 
    System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback((x) => 
    { 
     while (backgroundWorker1.IsBusy && backgroundWorker2.IsBusy) 
     { 
      System.Threading.Thread.Sleep(0); 
     } 
     // Code that is beging executed after all threads have ended. 
     myCode(); 
    })); 

    if (!backgroundWorker1.IsBusy) 
    { 
     backgroundWorker1.RunWorkerAsync(); 
    } 
    else if (!backgroundWorker2.IsBusy) 
    { 
     backgroundWorker2.RunWorkerAsync(); 
    }   
} 
+0

कारण देने के बिना डाउनवॉटिंग न तो सहायक और न ही अच्छा है। यह उत्तर पूछे गए प्रश्न का एक वैध उत्तर है और यह दिखाता है कि जितना संभव हो सके प्रश्नकर्ता से अधिक कोड का उपयोग करके डेडलॉक से बाहर निकलना है। – codingdave

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