2008-09-27 12 views
32

मैं अपने खाली समय में एक वेब क्रॉलिंग .NET ऐप पर काम कर रहा हूं, और इस ऐप की विशेषताओं में से एक जिसे मैं शामिल करना चाहता था, एक विशिष्ट थ्रेड को रोकने के लिए एक विराम बटन था।क्या अनिश्चित काल तक धागे को रोकने का कोई तरीका है?

मैं बहु-थ्रेडिंग के लिए अपेक्षाकृत नया हूं और मैं वर्तमान में समर्थित थ्रेड को अनिश्चित काल तक रोकने का कोई तरीका नहीं ढूंढ पाया है। मुझे सटीक कक्षा/विधि याद नहीं है, लेकिन मुझे पता है कि ऐसा करने का एक तरीका है लेकिन इसे .NET ढांचे द्वारा अप्रचलित के रूप में चिह्नित किया गया है।

क्या सी # .NET में एक कार्यकर्ता थ्रेड को अनिश्चित काल तक रोकने का कोई अच्छा सामान्य उद्देश्य तरीका है।

मेरे पास इस ऐप पर काम करने के लिए हाल ही में बहुत समय नहीं था और आखिरी बार मैंने इसे स्पर्श किया था .NET 2.0 ढांचे में था। मैं .NET 3.5 ढांचे में मौजूद किसी भी नई फीचर्स (यदि कोई है) के लिए खुला हूं, लेकिन मैं समाधान के बारे में जानना चाहता हूं जो कि 2.0 फ्रेमवर्क में भी काम करता है क्योंकि मैं काम पर इसका उपयोग करता हूं और यह अच्छा होगा बस मामले में पता है।

उत्तर

90

कभी भी Thread.Suspend का उपयोग न करें। इसके साथ बड़ी समस्या यह है कि 99% बार आप यह नहीं जान सकते कि वह थ्रेड क्या कर रहा है जब आप इसे निलंबित करते हैं। यदि उस धागे में ताला लगा है, तो आप डेडलॉक स्थिति में प्रवेश करना आसान बनाते हैं, ध्यान रखें कि जिस कोड को आप कॉल कर रहे हैं वह दृश्यों के पीछे ताले को प्राप्त/रिलीज़ कर सकता है। Win32 में एक समान API है: SuspendThread और ResumeThread

http://msdn.microsoft.com/en-us/library/ms686345(VS.85).aspx

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

अनिश्चित काल तक थ्रेड को निलंबित करने का उचित तरीका ManualResetEvent का उपयोग करना है। थ्रेड सबसे अधिक संभावना है, कुछ काम कर रहा है। धागा को निलंबित करने का सबसे आसान तरीका है, धागा है प्रत्येक यात्रा "जाँच" घटना के लिए इतना की तरह है:

while (true) 
{ 
    _suspendEvent.WaitOne(Timeout.Infinite); 

    // Do some work... 
} 

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

तुम इतनी तरह घटना बनाने होगा:

ManualResetEvent _suspendEvent = new ManualResetEvent(true); 

true पैरामीटर घटना बताता संकेत राज्य में बाहर शुरू करने के लिए।

आप धागा रोकना चाहते हैं, तो आप निम्न है:

_suspendEvent.Reset(); 

और धागा फिर से शुरू करने:

_suspendEvent.Set(); 

आप बाहर निकलने के लिए धागा संकेत करने के लिए इसी तरह की एक प्रणाली का उपयोग कर सकते हैं और दोनों घटनाओं पर इंतजार करें, यह पता लगाने के लिए कि कौन सी घटना संकेतित की गई थी।

बस मस्ती के लिए मैं एक पूर्ण उदाहरण उपलब्ध कराएँगे:

public class Worker 
{ 
    ManualResetEvent _shutdownEvent = new ManualResetEvent(false); 
    ManualResetEvent _pauseEvent = new ManualResetEvent(true); 
    Thread _thread; 

    public Worker() { } 

    public void Start() 
    { 
     _thread = new Thread(DoWork); 
     _thread.Start(); 
    } 

    public void Pause() 
    { 
     _pauseEvent.Reset(); 
    } 

    public void Resume() 
    { 
     _pauseEvent.Set(); 
    } 

    public void Stop() 
    { 
     // Signal the shutdown event 
     _shutdownEvent.Set(); 

     // Make sure to resume any paused threads 
     _pauseEvent.Set(); 

     // Wait for the thread to exit 
     _thread.Join(); 
    } 

    public void DoWork() 
    { 
     while (true) 
     { 
      _pauseEvent.WaitOne(Timeout.Infinite); 

      if (_shutdownEvent.WaitOne(0)) 
       break; 

      // Do the work here.. 
     } 
    } 
} 
15

Threading in C# ebook को सारांशित Thread.Suspend और thusly Thread.Resume:

पदावनत को निलंबित और फिर से शुरू तरीकों के दो स्वरूप हैं - खतरनाक और बेकार!

पुस्तक एक तुल्यकालन निर्माण एक जैसे AutoResetEvent या Monitor.Wait धागा निलंबित और पुनः चलाना प्रदर्शन करने के लिए उपयोग करने की सलाह।

+0

मैं जाकर कि ebook पढ़ने के लिए होगा। मुझे सस्पेंड/खुद को फिर से शुरू करने में कभी समस्या नहीं हुई है। –

0

उपरोक्त सुझावों के अलावा, मैं एक टिप जोड़ना चाहते हैं। कुछ मामलों में, पृष्ठभूमि वर्कर का उपयोग अपने कोड को सरल बना सकता है (विशेष रूप से जब आप DoWork और इसके अन्य कार्यक्रमों को परिभाषित करने के लिए अनाम विधि का उपयोग करते हैं)। यह मत करो -

0
अन्य लोगों ने कहा कि क्या के साथ लाइन में

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

-1

को निलंबित() और फिर से शुरू() depricated किया जा सकता है, लेकिन वे कोई रास्ता नहीं बेकार में हैं। यदि, उदाहरण के लिए, आपके पास एक लंबा काम है जो डेटा को बदलने में लंबा काम करता है, और उपयोगकर्ता इसे रोकना चाहता है, तो वह एक बटन पर क्लिक करता है। बेशक, आपको सत्यापन के लिए पूछना होगा, लेकिन साथ ही, आप नहीं चाहते हैं कि थ्रेड डेटा को बदलना जारी रखे, अगर उपयोगकर्ता फैसला करता है कि वह वास्तव में निरस्त करना चाहता है। उपयोगकर्ता को प्रतीक्षा करने के लिए प्रतीक्षा करने के दौरान थ्रेड को निलंबित करना, पुष्टिकरण संवाद पर हां या नहीं बटन केवल डेटा को बदलने से रोकने के लिए है, इससे पहले कि आप नामित निरस्त घटना को सिग्नल करें, जिससे इसे रोकने की अनुमति मिल सके। घटनाएं एक लूप वाले साधारण धागे के लिए अच्छी हो सकती हैं, लेकिन जटिल प्रसंस्करण के साथ जटिल धागे एक और मुद्दा है। निश्चित रूप से, को निलंबित() कभी नहीं, syncronising के लिए इस्तेमाल किया जाना चाहिए के बाद से इसकी उपयोगिता इस कार्य के लिए नहीं है।

बस मेरी राय।

1

मैं सिर्फ एक LoopingThread वर्ग जो एक कार्रवाई निर्माता को पारित कर दिया लूप को लागू किया। यह ब्रैनन की पोस्ट पर आधारित है। मैंने कुछ अन्य सामान WaitForPause(), WaitForStop(), और TimeBetween संपत्ति में डाल दिया है, जो उस समय को इंगित करता है जो अगली लूपिंग से पहले प्रतीक्षा की जानी चाहिए।

मैं भी एक do-जबकि पाश जबकि पाश बदलने का फैसला किया। यह हमें लगातार Start() और Pause() के लिए एक निर्धारक व्यवहार देगा। निर्धारक के साथ मेरा मतलब है कि कार्रवाई Start() कमांड के बाद कम से कम एक बार निष्पादित की जाती है। ब्रैनन के कार्यान्वयन में यह मामला नहीं हो सकता है।

मैं इस मामले की जड़ के लिए कुछ चीजें छोड़े गए।चीजें जैसे "थ्रेड पहले ही शुरू हो गया था" की जांच करें, या IDisposable पैटर्न।

public class LoopingThread 
{ 
    private readonly Action _loopedAction; 
    private readonly AutoResetEvent _pauseEvent; 
    private readonly AutoResetEvent _resumeEvent; 
    private readonly AutoResetEvent _stopEvent; 
    private readonly AutoResetEvent _waitEvent; 

    private readonly Thread _thread; 

    public LoopingThread (Action loopedAction) 
    { 
    _loopedAction = loopedAction; 
    _thread = new Thread (Loop); 
    _pauseEvent = new AutoResetEvent (false); 
    _resumeEvent = new AutoResetEvent (false); 
    _stopEvent = new AutoResetEvent (false); 
    _waitEvent = new AutoResetEvent (false); 
    } 

    public void Start() 
    { 
    _thread.Start(); 
    } 

    public void Pause (int timeout = 0) 
    { 
    _pauseEvent.Set(); 
    _waitEvent.WaitOne (timeout); 
    } 

    public void Resume() 
    { 
    _resumeEvent.Set(); 
    } 

    public void Stop (int timeout = 0) 
    { 
    _stopEvent.Set(); 
    _resumeEvent.Set(); 
    _thread.Join (timeout); 
    } 

    public void WaitForPause() 
    { 
    Pause (Timeout.Infinite); 
    } 

    public void WaitForStop() 
    { 
    Stop (Timeout.Infinite); 
    } 

    public int PauseBetween { get; set; } 

    private void Loop() 
    { 
    do 
    { 
     _loopedAction(); 

     if (_pauseEvent.WaitOne (PauseBetween)) 
     { 
     _waitEvent.Set(); 
     _resumeEvent.WaitOne (Timeout.Infinite); 
     } 
    } while (!_stopEvent.WaitOne (0)); 
    } 
} 
0

अगर कोई तुल्यकालन आवश्यकताएँ हैं:

Thread.Sleep(Timeout.Infinite);

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

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