2009-04-29 3 views
47

मैं एक विंडोज़ एप्लीकेशन लिख रहा हूं जो बार-बार डिजिटल आईओ कार्यों का अनुक्रम चलाता है।पृष्ठभूमि कार्यकर्ता को पूरी तरह से "मारने" कैसे करें?

जब उपयोगकर्ता "स्टार्ट" बटन पर क्लिक करता है तो यह अनुक्रम प्रारंभ होता है, और यह पृष्ठभूमि वर्कर 1_DoWork() में पृष्ठभूमि कार्यकर्ता द्वारा किया जाता है।

हालांकि, ऐसे अवसर होते हैं जब मुझे "यह पृष्ठभूमि कार्यकर्ता वर्तमान में व्यस्त ......." त्रुटि संदेश प्राप्त करता है।

मैं कोड में निम्नलिखित को लागू करने की सोच रहा हूँ, थोड़ी देर के पाश का उपयोग कर कार्रवाई का एक और अनुक्रम शुरू करने से पहले पृष्ठभूमि कार्यकर्ता "मारने" के लिए द्वारा: जाएगा

if (backgroundWorker1.IsBusy == true) 
{ 

    backgroundWorker1.CancelAsync(); 
    while (backgroundWorker1.IsBusy == true) 
    { 
     backgroundWorker1.CancelAsync(); 
    } 

    backgroundWorker1.Dispose(); 

} 

backgroundWorker1.RunWorkerAsync(); 

मुझे लगता है कि मेरी मुख्य चिंता का विषय है, BackgroundWorker1 अंततः "मारे गए" हो? अगर ऐसा होगा, तो इसे पूरा करने में काफी समय लगेगा?

क्या यह कोडिंग मुझे अनंत लूप में लाएगी?

+2

को मारने के लिए सही करने के लिए मारने के सेट क्यों आप एक पाश की जरूरत है? एक बार इसका मतलब यह नहीं होगा कि यह अब व्यस्त नहीं है? – Louis

+0

आगे, आवेदन में उचित है कि वहां एक नींद डालना बुद्धिमान होगा। इसके अलावा, क्या होता है यदि कार्यकर्ता वैध रूप से व्यस्त है? क्या आप अभी भी इसे एक प्रक्रिया के बीच में मारना चाहते हैं? मुझे लगता है कि पृष्ठभूमि कार्यकर्ता को अनिश्चित काल तक व्यस्त होने के लिए मजबूर करना बंद करना बुद्धिमान हो सकता है। – Louis

उत्तर

16

मैं राय है कि धागे उनके खुद अपने स्वयं के जीवन सहित, साध्य जितना संसाधन के लिए जिम्मेदार होना चाहिए की हूँ।

आमतौर पर धागे को उनके दायरे से बाहर करने के लिए एक बुरा विचार है। स्वयं को बंद करने के लिए थ्रेड को संदेश भेजने के लिए इंजीनियर किए गए अनुप्रयोगों को बहु-थ्रेडेड व्यवहार से संबंधित बहुत कम समस्याएं होती हैं।

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

इसका मतलब है कि अगर यह संदेश के लिए दिखना चाहिए:

  • यह मुख्य पाश है में, यदि कोई हो।
  • समय-समय पर किसी भी लंबे समय तक चलने वाले लूप में।

संदेश के साथ इसे बंद करने वाला थ्रेड प्रतीक्षा करना चाहिए (लेकिन निश्चित रूप से जीयूआई को रोकना नहीं है)।

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

लेकिन अभी भी अपने आवेदन को आर्किटेक्ट करना आसान है ताकि आप अपने भाग्य के थ्रेड मास्टर को छोड़ सकें।

+2

यदि धागा बाहरी संसाधन तक पहुंचता है जो थ्रेड को अवरुद्ध कर सकता है, तो थ्रेड को मारना एकमात्र विकल्प हो सकता है – HamoriZ

+0

इसलिए वाक्यांश: "जितना अधिक व्यावहारिक" :-) – paxdiablo

-1

मैं एक ही समस्या हो रही थी, मैं अगर यह मदद मिलेगी यकीन नहीं है, लेकिन मैं अपनी पृष्ठभूमि कार्यकर्ता के भीतर एक लूप है अनुमान लगा रहा हूँ या यह बाहर निकल जाएगा। आपको अपनी लूप को अंदर रखने की क्या ज़रूरत है।

अपनी पृष्ठभूमि कार्यकर्ता अंदर रख:

while (backgroundworker1.CancellationPending == false) 
{ 
    //Put your code in here 
} 

इस BackgroundWorker को मारने के लिए, आपको अपने बटन में डाल कर सकते हैं:

BackgroundWorker1.CancelAsync() 

मुझे आशा है कि इस मदद करता है।

+3

कृपया अपना स्वरूपण और अंग्रेजी साफ़ करें! –

+1

मान्य उत्तर लेकिन भयानक स्वरूपण ... – John

+0

कृपया सीखें कि कैसे बात करें। – ro0ter

69

आप (क्रिस सेल्स द्वारा प्रबंधित धागे निरस्त किया जा रहा है और ThreadAbortException के बारे में "Plumbing the Depths of the ThreadAbortException Using Rotor" के बारे में अधिक जानकारी के लिए) कुछ इस तरह उपयोग कर सकते हैं:

public class AbortableBackgroundWorker : BackgroundWorker 
{ 

    private Thread workerThread; 

    protected override void OnDoWork(DoWorkEventArgs e) 
    { 
     workerThread = Thread.CurrentThread; 
     try 
     { 
      base.OnDoWork(e); 
     } 
     catch (ThreadAbortException) 
     { 
      e.Cancel = true; //We must set Cancel property to true! 
      Thread.ResetAbort(); //Prevents ThreadAbortException propagation 
     } 
    } 


    public void Abort() 
    { 
     if (workerThread != null) 
     { 
      workerThread.Abort(); 
      workerThread = null; 
     } 
    } 
} 

उपयोग:

backgroundWorker1 = new AbortableBackgroundWorker(); 
//... 
backgroundWorker1.RunWorkerAsync(); 

if (backgroundWorker1.IsBusy == true) 
{ 
    backgroundWorker1.Abort(); 
    backgroundWorker1.Dispose(); 
} 
+0

मुझे यह बहुत पसंद है। यह वास्तव में नौकरी करने लगता है। मुझे पृष्ठभूमिवर्कर में कुछ जटिल चीजें चल रही हैं, लेकिन इसे पूरा होने तक कुछ भी लिखा नहीं जा रहा है। –

+3

बीटीडब्लू, थ्रेड.एबॉर्ट के साथ थ्रेड को मारना अभी भी खतरनाक है, क्योंकि एसिंक्रोनस अपवादों के संदर्भ में .net फ्रेमवर्क में हर वर्ग मजबूत नहीं है। लेकिन अगर आप जानते हैं कि आप क्या कर रहे हैं - ठीक है। –

+0

मैं इस कोड को पहली बार ढूंढने में बहुत खुश था, लेकिन जब मैंने कोशिश की तो थ्रेड के लिए उम्र बढ़ गई ... मुझे इस तरह के व्यवहार की उम्मीद नहीं थी और मैं थोड़ा उलझन में हूं। वास्तव में कोई विचार नहीं है कि यह इतना लंबा क्यों लगता है –

0

मैं एक साथ रखा वह (मुझे लगता है) नौकरी करता है। अगर मुझे लगता है तो कृपया मुझे बताएं। यह कैसे काम करता है इसका एक सरल उदाहरण है।

var backgroundWorker = new BackgroundWorker(){WorkerSupportsCancellation = true}; 

backgroundWorker.DoWork += (sender, args) => 
     {     
       var thisWorker = sender as BackgroundWorker; 
       var _child = new Thread(() => 
               { 
                //..Do Some Code 

               }); 
       _child .Start(); 
       while (_child.IsAlive) 
       { 
        if (thisWorker.CancellationPending) 
        { 
         _child.Abort(); 
         args.Cancel = true; 
        } 
        Thread.SpinWait(1); 
       }     
     }; 

backgroundWorker.RunWorkerAsync(parameter); 
//..Do Something... 
backgroundWorker.CancelAsync(); 

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

कृपया मुझे बताएं कि क्या मैं दीवार के खिलाफ अपने सिर को टक्कर लगी हूं लेकिन ऐसा लगता है कि यह ठीक काम करता है .. लेकिन थ्रेड के साथ समस्या यह नहीं है .. अलग-अलग समय पर आप इसे चलाने के दौरान अलग-अलग परिणाम प्राप्त कर सकते हैं।

+0

-1: नए डिजाइन सुझाव में '.bort()' के लिए। –

+2

बहुत, एक थ्रेड को बाहरी रूप से 'abort' करने के लिए बहुत खतरनाक है। कृपया पढ़ें: http://www.interact-sw.co.uk/iangblog/2004/11/12/cancellation। असल में, यह ** तीन ** तरीकों में बहुत गलत है: (1) एक अनावश्यक अतिरिक्त धागा बनाना, (2) उस पर व्यस्त-प्रतीक्षा, और (3) उचित सफाई के बिना संभावित संभावित क्षण पर इसे निरस्त करना। – Aaronaught

+0

उपर्युक्त प्रतिक्रिया भी बच्चे-थ्रेड + निरस्त प्रकार के समाधान का उपयोग करती है। क्या इससे निपटने का कोई बेहतर तरीका है? – Rob

-1
public class abortableBackgroundworker: BackgroundWorker 
{ 
    public bool Kill = false; 

    protected override void OnDoWork(DoWorkEventArgs e) 
    { 


     var _child = new Thread(() => 
     { 
      while (!Kill) 
      { 

      } 
      e.Cancel = true;//..Do Some Code 

     }); 
     _child.Start(); 
     base.OnDoWork(e); 

    } 



} 

आप धागा और कोई बीच में बंद करें समस्या :)

+5

दोस्त इस कोड ने मेरे 24-कोर ज़ीऑन एक्सडी को मार डाला –

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

  • कोई संबंधित समस्या नहीं^_^