2010-01-08 10 views
5

मैं एक लंबी गणना (एक समय में केवल एक ही गणना) करने के लिए पृष्ठभूमिवर्कर का उपयोग कर रहा हूं।पृष्ठभूमिवर्कर को रद्द करना, दौड़ को रोकने के लिए कैसे करें

उपयोगकर्ता को कार्यकर्ता को रद्द करने की संभावना है (कॉल करने वाले कर्मचारी। कैंसलएसिंक)।

कार्यकर्ता में। डॉकवर्क विधि मैं समय-समय पर लंबित ध्वज रद्द करने की जांच करता हूं और फिर विधि से वापस आ जाता हूं।

फिर पूरा कार्यक्रम कार्यकर्ता से उठाया गया है और मैं जांच सकता हूं कि कार्यकर्ता रद्द कर दिया गया था। इसके अलावा, और यह महत्वपूर्ण बात है, जब रद्द किया जाता है तो मैं कुछ अतिरिक्त सफाई करता हूं।

मुझे यकीन है कि उपयोगकर्ता कार्यकर्ता को रद्द कर सकता है और यह पहले से ही DoWork विधि से वापस आ गया है, तो समस्या हो सकती है। उस स्थिति में मैं वास्तव में जानना चाहता हूं कि कार्यकर्ता रद्द कर दिया गया था इसलिए मैं सफाई कर सकता था ...

क्या कार्यकर्ता की सफाई प्रक्रिया को रद्द करने के लिए एक बेहतर तरीका है?

उत्तर

2

आपका DoWork ईवेंट हैंडलर समय-समय पर shoud BackgroundWorker.CancellationPending, और लौटने अगर यह रद्द कर दिया गया इससे पहले कि सत्य पर DoWorkEventArgs.Cancel निर्धारित किया है।

आपका RunWorkerCompleted ईवेंट हैंडलर अगर DoWork ईवेंट हैंडलर रद्द (सेट को सही पर DoWorkEventArgs.Cancel) निर्धारित करने के लिए RunWorkerCompletedEventArgs.Cancelled संपत्ति की जांच होनी चाहिए।

दौड़ की स्थिति की स्थिति में, ऐसा हो सकता है कि उपयोगकर्ता ने रद्दीकरण का अनुरोध किया (BackgroundWorker.CancellationPending सत्य है) लेकिन कार्यकर्ता इसे नहीं देख पाया (RunWorkerCompletedEventArgs.Cancelled गलत है)। आप यह निर्धारित करने के लिए इन दो गुणों का परीक्षण कर सकते हैं कि यह हुआ है, और जो कुछ भी आप चुनते हैं (या तो इसे सफल समापन के रूप में देखें - क्योंकि कार्यकर्ता वास्तव में सफलतापूर्वक समाप्त होता है, या रद्दीकरण के रूप में - क्योंकि उपयोगकर्ता ने रद्द कर दिया है और किसी की परवाह नहीं है अधिक)।

मुझे कोई ऐसी स्थिति दिखाई नहीं दे रही है जहां क्या हुआ उसके बारे में कोई अस्पष्टता है।

संपादित

टिप्पणी के जवाब में - अगर वहाँ कई वर्गों कि CancellationPending का पता लगाने की जरूरत है, वहाँ कोई वास्तव में कोई है कि उन्हें करने के लिए अनुमति देता है इस तरह के BackgroundWorker के रूप में इन वर्गों के लिए एक प्रकार के लिए एक संदर्भ पारित करने के लिए विकल्प है इस जानकारी को पुनः प्राप्त करें। आप इसे इंटरफ़ेस में समझा सकते हैं, जो मैं सामान्य रूप से पृष्ठभूमि प्रतिक्रियाओं के बारे में एक प्रश्न के लिए इस प्रतिक्रिया में वर्णित करता हूं। लेकिन आपको अभी भी उस प्रकार के संदर्भ को पारित करने की आवश्यकता है जो इस कार्यकर्ता को आपके कार्यकर्ता वर्गों में लागू करे।

आप अपने कार्यकर्ता कक्षाएं स्थापित करने के लिए DoWorkEventArgs.Cancel आप या तो चारों ओर इस के लिए एक संदर्भ गुजरती हैं, या एक अलग सम्मेलन को अपनाने की आवश्यकता होगी सक्षम होने के लिए चाहते हैं (उदाहरण के लिए एक बूलियन वापसी मान या कस्टम अपवाद) है कि अपने कार्यकर्ता कक्षाएं इंगित करने के लिए अनुमति देता है रद्दीकरण हुआ है।

+1

यह वास्तव में स्पष्ट स्पष्टीकरण है। हालांकि, चूंकि काम पूरी तरह से "DoWork" विधि में नहीं किया जाता है, इसलिए मुझे इवेंटआर्ग को हर वर्ग में पास करना होगा जो रद्दीकरण की जांच करेगा और मेरे पास लगभग 30 वर्ग (गहरी अनुकूलन समस्या) है। यह व्यवहार्य है लेकिन मुझे लगता है कि यह एक पिटा होगा ... साथ ही मुझे उन वर्गों को रद्दीकरण का प्रबंधन करना पसंद नहीं है। मैं अभी भी एक बेहतर तरीका तलाश रहा हूँ। –

+0

"मुझे उन वर्गों को रद्दीकरण का प्रबंधन करने की इच्छा नहीं है" - मुझे आपकी चिंता नहीं आती है। यदि हां, तो उन्हें रद्दीकरण का प्रबंधन न करें! इसके बजाय, इन कक्षाओं में से कोई भी आपके मुख्य DoWork विधि पर नियंत्रण लौटने पर केवल रद्दीकरण की जांच करें। – Joe

+0

वे आंतरिक कक्षाएं वास्तव में लंबी गणना कर रही हैं और इसलिए वे अक्सर वापस नहीं आती हैं। –

0

क्या कोई कारण है कि आप असीमित रूप से चलने वाली विधि के अंत में सफाई नहीं कर सकते हैं?

मैं आम तौर पर इस

private void MyThreadMethod() 
{ 
    try 
    { 
     // Thread code 
    } 
    finally 
    { 
     // Cleanup 
    } 
} 

की तरह एक संरचना का उपयोग मैं केवल कार्य करने के लिए पूरा घटना का उपयोग किया है यूआई अद्यतन की तरह, धागा के बाद साफ करने के लिए नहीं।

+1

हाँ, मैं पृष्ठभूमि कार्यकर्ता में सफाई नहीं कर सकता ... मुझे इसे यूआई थ्रेड पर करने की आवश्यकता है। –

+1

क्या आप एक बार से अधिक बार आग लग रहे हैं? यदि ऐसा है, तो आप यह सुनिश्चित करने के लिए अपने ईवेंट हैंडलर में लॉक (...) {} ब्लॉक का उपयोग कर सकते हैं ताकि कोड एक समय में केवल एक बार निष्पादित किया जा सके, और एक ध्वज सेट कर रहा है जो सफाई करता है (उस फ्लैग को अपनी पहली चीज़ में जांचें लॉक ब्लॉक और सेट न होने पर केवल क्लीनअप कोड चलाएं)। –

0

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

यदि उपयोगकर्ता एक कुंजी प्रेस के माध्यम से भी रद्द कर सकता है तो आपको उसे भी अक्षम करने की आवश्यकता होगी।

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

कार्यकर्ता ने अपना काम करने के बाद रद्द ध्वज को देखने की आवश्यकता क्यों है? क्या आप अभी भी वापस रोल करना चाहते हैं जो कभी भी बदला गया था?

+0

असल में, समस्या उपयोगकर्ता को कई बार रद्द करने से नहीं रोक रही है ... समस्या यह सुनिश्चित करने के लिए और अधिक है कि कार्यकर्ता ने अपना काम पूरा करने के बाद भी रद्द ध्वज देखा और पूरा कार्यक्रम प्राप्त हुआ। –

1

आपको यूआई थ्रेड पर चलने के बाद RunWorkerCompleted ईवेंट हैंडलर में दौड़ न होने की गारंटी है। यह हमेशा काम करना चाहिए:

private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { 
    var bgw = sender as BackgroundWorker; 
    if (e.Cancelled || bgw.CancellationPending) { 
    // etc.. 
    } 
} 
+0

काम नहीं लग रहा है। उपरोक्त उत्तर पर मेरी टिप्पणी देखें। – user12861

2

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

Public Class CancelTrackingBackgroundWorker 
    Inherits System.ComponentModel.BackgroundWorker 
    Public CancelRequested As Boolean = False 
    Public Sub TrackableCancelAsync() 
    Me.CancelRequested = True 
    Me.CancelAsync() 
    End Sub 
End Class 

(कैसे कष्टप्रद CancelAsync वैसे, overridable नहीं है।) तो मैं पुराने CancelAsync के बजाय TrackableCancelAsync संपर्क करें, मैं के लिए जाँच मेरे कोड में यह नया CancelRequested ध्वज। जब तक आप केवल यूआई थ्रेड (मानक होने के रूप में) से कॉल करते हैं और जांचते हैं, तो आपको अपने थ्रेडिंग मुद्दों का ख्याल रखना चाहिए।

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