2011-06-12 17 views
5

मुझे स्ट्रीम ऑब्जेक्ट मिला है और मैं एक बफर में पढ़ने (स्पष्ट रूप से) शुरू करने के लिए BeginRead का उपयोग कर रहा हूं; एक बार पढ़ने पूर्ण होने के बाद AsyncCallback फ़ंक्शन को कॉल किया जाता है। इस फ़ंक्शन के भीतर मैं जांच सकता हूं कि क्या उपयोगकर्ता अगला 'ब्लॉक' प्राप्त करना चाहता है और फिर से BeginRead प्रक्रिया शुरू करना चाहता है।AsyncCallback फ़ंक्शन के बाहर एक एसिंक्रोनस स्ट्रीम को रोकना

मेरी समस्या यह है कि स्ट्रीम अभी भी पढ़ रहा है, जबकि स्ट्रीम अभी भी पढ़ रहा है (इसलिए AsyncCallback फ़ंक्शन कहा जाता है), तो मैं स्ट्रीम के पढ़ने को कैसे रद्द कर सकता हूं?

बस इस मुद्दे को और समझाने के लिए - ऐसा लगता है कि अगर मैं स्ट्रीमवर्क रीड विधि या एसिंक्रोनस BeginRead विधि के साथ पृष्ठभूमिवर्कर का उपयोग करता हूं तो मुझे वही परिणाम मिलेंगे। स्ट्रीम को पढ़ना बंद करना चाहिए या नहीं, यह जांचने से पहले उपयोगकर्ता को पढ़ने के लिए रीड/स्टार्ट रीड विधि के लिए किसी भी समय की प्रतीक्षा करने के लिए छोड़ दिया जा सकता है।

संपादित करें: नीचे दिया गया कोड नौकरी करना चाहिए, मैं सी # में कुछ भी सभ्य होने से दस लाख मील दूर हूं, इसलिए इसमें कुछ बग हो सकते हैं क्योंकि मुझे शक है कि यह सही है, हालांकि यह समाधान का प्रदर्शन करता है ।

संक्षेप में, CWorkManager धागे की एक निश्चित संख्या का प्रबंधन करता है (जो एक CWorkerDetail कक्षा में आयोजित होते हैं)। प्रत्येक CWorkerDetail की स्थिति होती है, जिसका अर्थ है कि कार्यकर्ता शुरू किया जा सकता है, जिसका अर्थ है कि कार्यकर्ता स्रोत से पढ़ रहा है, जिसके दौरान कार्यकर्ता तुरंत रोक दिया जा सकता है, EWriting जो डिस्क को पढ़ने वाले डेटा को सहेजता है - इसे तुरंत बंद नहीं किया जा सकता है और थ्रेड बंद होने से पहले यह प्रक्रिया पूरी होनी चाहिए। अंत में EAborting है जो प्रबंधक द्वारा निर्धारित किया जाता है यदि कार्यकर्ता जल्द से जल्द निरस्त किया जाना चाहिए; अभी यह केवल तभी सेट है जब कार्यकर्ता किसी ऐसे व्यक्ति के बीच में है जिसे बाधित नहीं किया जा सकता है (जैसे डिस्क पर लिखना)।

अभी, वास्तव में कोई भी पढ़ना या लिखना नहीं है, क्योंकि यह केवल मुख्य समाधान को जटिल करेगा (जो मूल रूप से केवल स्टॉपवर्कर फ़ंक्शन है जो यह देखने के लिए CWorker का ध्वज जांचता है कि यह तुरंत निरस्त हो सकता है); जैसे हम थ्रेड को सोते हैं।

जीयूआई पक्ष सिर्फ एक सूची बॉक्स (जो प्रत्येक कार्यकर्ता की स्थिति दिखाता है) और एक स्टॉप और स्टार्ट बटन के साथ काफी सरल है। सभी कोड से नीचे है, उम्मीद है कि इस मदद करता है किसी को है, लेकिन जैसा कि मैंने कहा मैं के साथ सी # प्रतिभाशाली तो कीड़े आदि के लिए बाहर देखने के लिए कृपया नहीं कर रहा हूँ ...

CWorkManager.cs:


using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Threading; 


namespace ThreadApplication { 


    //A worker that spawns a number of threads (managed internally) that does nothing useful at all. 
    public class CWorkManager { 


     //The status of the worker. 
     public enum EWorkerStatus { 
      EWaiting, 
      EReading, 
      EWriting, 
      EAborting, 
     } 


     //Holds all data relevant to the worker. 
     private class CWorkerDetails { 

      //Simple variables. 
      private readonly Object _Lock=new Object(); 
      private Thread gThread; 
      private EWorkerStatus gStatus; 
      private CWorkManager gParentInstance; 
      private int gIndex; 

      //Simple constructor. 
      public CWorkerDetails(int aIndex, CWorkManager aParentInstance, Thread aThread, EWorkerStatus aStatus) { 
       gIndex=aIndex; 
       gParentInstance=aParentInstance; 
       gThread=aThread; 
       gStatus=aStatus; 
      } 

      //Simple get set methods. 
      public Thread GetThread() { lock(_Lock) { return gThread; } } 
      public EWorkerStatus GetStatus() { lock(_Lock) { return gStatus; } } 

      //Sets the status and automatically updates the GUI. 
      public void SetStatus(EWorkerStatus aStatus) { 
       lock(_Lock) { 
        gStatus=aStatus; 
        Form1.gInstance.Invoke(new UpdateGUIDelegate(gParentInstance.UpdateGUI), new object[] { gIndex, GetStatus() }); 
       } 
      } 

     } 


     //Worker variable. 
     private List<CWorkerDetails> gWorkers; 


     //Simple constructor. 
     public CWorkManager(int aWorkerCount){ 
      gWorkers=new List<CWorkerDetails>(); 
      for(int tIndex=0; tIndex<aWorkerCount; tIndex++) 
       gWorkers.Add(null); 
     } 


     //Creates and starts the worker. 
     public void StartWorker(int aWorkerIndex) { 

      //Create a new worker if there is none or if it is waiting to start. 
      if(gWorkers.ElementAt(aWorkerIndex)==null||gWorkers.ElementAt(aWorkerIndex).GetStatus()==EWorkerStatus.EWaiting) 
       gWorkers[aWorkerIndex]=new CWorkerDetails(aWorkerIndex, this, new Thread(new ParameterizedThreadStart(WorkerMethod)), EWorkerStatus.EWaiting); 

      //If the worker is waiting to start, then start. 
      if(gWorkers.ElementAt(aWorkerIndex).GetStatus()==EWorkerStatus.EWaiting) 
       gWorkers.ElementAt(aWorkerIndex).GetThread().Start(gWorkers.ElementAt(aWorkerIndex)); 
     } 


     //Stops the worker. 
     public void StopWorker(int aWorkerIndex) { 

      //Do nothing if the worker is null. 
      if(gWorkers.ElementAt(aWorkerIndex)==null) 
       return; 

      //Do nothing if the worker is waiting. 
      if(gWorkers.ElementAt(aWorkerIndex).GetStatus()==EWorkerStatus.EWaiting) 
       return; 

      //If the worker is reading we can abort instantly. 
      if(gWorkers[aWorkerIndex].GetStatus()==EWorkerStatus.EReading) { 
       gWorkers[aWorkerIndex].GetThread().Abort(); 
       gWorkers[aWorkerIndex].SetStatus(EWorkerStatus.EWaiting); 
       return; 
      } 

      //Since the worker is not reading or waiting, we have to request the 
      //worker to abort by itself. 
      gWorkers[aWorkerIndex].SetStatus(EWorkerStatus.EAborting); 

     } 


     //Updates the GUI. 
     private delegate void UpdateGUIDelegate(int aIndex, EWorkerStatus aStatus); 
     private void UpdateGUI(int aIndex, EWorkerStatus aStatus) { 
      Form1.gInstance.SetThreadStatus(aIndex, aStatus); 
     } 


     //This method is where all the real work happens. 
     private void WorkerMethod(Object aWorker) { 

      //Fetch worker. 
      CWorkerDetails mWorker=(CWorkerDetails)aWorker; 

      //Loop forever, the thread will exit itself when required. 
      while(true) { 

       //Is the worker status aborting - if so we stop here. 
       if(mWorker.GetStatus()==EWorkerStatus.EAborting) { 
        mWorker.SetStatus(EWorkerStatus.EWaiting); 
        return; 
       } 

       //This would normally be reading from a stream which would cause the thread 
       //to block, simulate this by just sleeping the thread. 
       mWorker.SetStatus(EWorkerStatus.EReading); 
       Thread.Sleep(3000); 

       //Is the worker status aborting - if so we stop here. 
       if(mWorker.GetStatus()==EWorkerStatus.EAborting) { 
        mWorker.SetStatus(EWorkerStatus.EWaiting); 
        return; 
       } 

       //All data has been read, set status to writing and again simulate by 
       //sleeping the thread. 
       mWorker.SetStatus(EWorkerStatus.EWriting); 
       Thread.Sleep(3000); 

      } 

     } 

    } 


} 

फॉर्म 1।सीएस:


शामिल है:

  • सूची बॉक्स (ListBox_WorkerStatus)
  • एक बटन (Button_Start)
  • एक बटन (Button_Stop)

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Windows.Forms; 


namespace ThreadApplication { 


    public partial class Form1:Form { 


     public static Form1 gInstance; 
     private CWorkManager gManager; 


     public Form1() { 
      InitializeComponent(); 
      Button_Start.Click+=new EventHandler(Button_Start_Click); 
      Button_Stop.Click+=new EventHandler(Button_Stop_Click); 
      gInstance=this; 
      for(int tIndex=0; tIndex<5; tIndex++) 
       ListBox_WorkerStatus.Items.Add("Created"); 
      gManager=new CWorkManager(ListBox_WorkerStatus.Items.Count); 
     } 


     public void SetThreadStatus(int aIndex, CWorkManager.EWorkerStatus aStatus) { 
      ListBox_WorkerStatus.Items[aIndex]=aStatus.ToString(); 
     } 


     private void Button_Start_Click(object sender, EventArgs e) { 
      if(ListBox_WorkerStatus.SelectedIndex>=0) { 
       gManager.StartWorker(ListBox_WorkerStatus.SelectedIndex); 
      } 
     } 


     private void Button_Stop_Click(object sender, EventArgs e) { 
      if(ListBox_WorkerStatus.SelectedIndex>=0) { 
       gManager.StopWorker(ListBox_WorkerStatus.SelectedIndex); 
      } 
     } 

     private void Form1_FormClosed(object sender, FormClosedEventArgs e) { 
      for(int tIndex=0; tIndex<ListBox_WorkerStatus.Items.Count; tIndex++) { 
       gManager.StopWorker(tIndex); 
      } 
     } 


    } 


} 

उत्तर

0

उपयोग BackgroundWorker

BackgroundWorker backgroundWorker1= new backgroundWorker() 

private void InitializeBackgroundWorker() 
{ 
     backgroundWorker1.DoWork += 
      new DoWorkEventHandler(backgroundWorker1_DoWork); 

     backgroundWorker1.WorkerSupportsCancellation = true; 
} 



private void backgroundWorker1_DoWork(object sender, 
     DoWorkEventArgs e) 
{ 
     BackgroundWorker worker = sender as BackgroundWorker; 

     e.Result = YourWorkToDo(); 
} 

public void Start() 
{ 
    backgroundWorker1.RunWorkerAsync() 
} 

public voic Cancel() 
{ 
    backgroundWorker1.CancelAsync(); 
{ 

यदि आप चाहते हैं और अधिक मदद की छुट्टी टिप्पणी

+0

मैं माफी चाहता, मैं काफी समझ में नहीं आता कि कैसे है कि के रूप में मदद मिलेगी कर रहा हूँ मुझे पृष्ठभूमिवर्कर थ्रेड (जो गड़बड़ी का कारण बन सकता है) को अचानक समाप्त करने के अलावा, सिंक्रनाइज़ पढ़ने को रोकने के लिए पृष्ठभूमिवर्कर की आवश्यकता होगी, मुझे नहीं लगता कि यह कैसे काम करेगा? – R4D4

+0

[यहां देखें] (http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx) –

+0

कोड के लिए धन्यवाद, हालांकि मुझे लगता है कि मूल समस्या मौजूद हो सकती है - उपयोगकर्ता DoWork फ़ंक्शन को अवरुद्ध करना बंद करने से पहले स्ट्रीम की रीड विधि के लिए प्रतीक्षा कर दिया जा सकता है इससे पहले कि यह पृष्ठभूमि कार्यकर्ता की रद्दीकरण की संपत्ति को देख सके। – R4D4

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