Frage

Ich habe ein Stream -Objekt und ich verwende beginread, um (offensichtlich) in einen Puffer zu lesen. Die Asynccallback -Funktion wird aufgerufen, sobald die Lesung abgeschlossen ist. Innerhalb dieser Funktion kann ich überprüfen, ob der Benutzer den nächsten "Block" erhalten und den BeginnRead -Prozess erneut starten möchte.

Das Problem, das ich habe, ist, dass der Benutzer möglicherweise abbrechen, während der Stream noch liest (also bevor die Asynccallback -Funktion aufgerufen wird). Wie kann ich also das Lesen des Streams abbrechen?

Nur um das Problem weiter zu erklären - es scheint, dass ich das gleiche Ergebnis hätte, wenn ich einen Hintergrundarbeiter mit der Streams -Lesemethode oder der asynchronen BeginnRead -Methode verwende. Der Benutzer könnte auf eine längere Zeit warten, bis die Lese-/beginread -Methode abgeschlossen ist, bevor ich prüfen kann, ob der Stream aufhören sollte zu lesen.

Bearbeiten: Der folgende Code sollte den Job erledigen, ich bin eine Million Meilen entfernt von etwas Anständigem in C#, also kann er ein paar Fehler haben, da ich bezweifle, dass es perfekt ist, obwohl er die Lösung demonstriert.

Kurz gesagt, der CWWERMANAGER verwaltet eine bestimmte Anzahl von Threads (die innerhalb einer CworkerDetail -Klasse gehalten werden). Jeder CworkerDetail hat einen Status, der ewaiting sein kann, was bedeutet, dass der Arbeiter gestartet werden kann. Dies bedeutet, dass der Arbeiter von einer Quelle liest. Während dieser Zeit kann der Arbeiter sofort gestoppt werden, was die Daten spart, die die Daten auf der Festplatte gelesen wurden - Dies kann nicht sofort gestoppt werden und dieser Vorgang muss abgeschlossen werden, bevor der Thread gestoppt wird. Schließlich gibt es Eaboring, die vom Manager festgelegt wird, wenn der Arbeitnehmer so schnell wie möglich abgebrochen werden sollte. Derzeit ist dies nur festgelegt, wenn sich der Arbeiter mitten in etwas befindet, das nicht unterbrochen werden kann (z. B. das Schreiben auf die Festplatte).

Im Moment gibt es tatsächlich keine Lektüre oder Schreiben, da dies nur die Hauptlösung kompliziert würde (was im Grunde genommen nur die Stopworker -Funktion ist, die ein Flag des CWWER überprüft, um festzustellen, ob es sofort abbrechen kann). Als solches lassen wir einfach den Faden schlafen.

Die GUI -Seite ist ziemlich einfach mit nur einer Listbox (die den Status jedes Arbeiters anzeigt) und eine Schaltfläche Stopp -and -Start. Der gesamte Code ist unten. Ich hoffe, dies hilft jemandem, aber wie ich sage, ich bin nicht brillant mit C#. Bitte achten Sie auf Fehler usw. ...

CWWERMANAGER.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);

            }

        }

    }


}

Form1.cs:


Enthält:

  • Ein Listenfeld (Listbox_WormStatus)
  • Eine Schaltfläche (Button_start)
  • Eine Schaltfläche (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);
            }
        }


    }


}

War es hilfreich?

Lösung

Verwenden Sie Hintergrundarbeiter

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();
{

Wenn Sie mehr Hilfe wünschen, hinterlassen Sie einen Kommentar ab

Andere Tipps

Bitte schauen Sie sich anAbbrechen beginread Dies

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top