Laden...

Class im Hintergrund ausführen und Methoden davon aufrufen?

Erstellt von JMano vor 10 Jahren Letzter Beitrag vor 10 Jahren 2.526 Views
J
JMano Themenstarter:in
38 Beiträge seit 2013
vor 10 Jahren
Class im Hintergrund ausführen und Methoden davon aufrufen?

Hi,

Ich habe eine Klasse (myProcessor) die ich gerne im Background ausführen würde,
so, dass ich dann darauf aus meinem normalen Programmfluss (Konsolen-Anwendung) die Methoden (Starting/Stopping) aufrufen kann.

Wie kann ich das mit C#.Net bewerkstelligen?

Wenn ich da versuche in Threads zu starten klappt das mim Stoppen nicht mehr ...


Class myProcessor
{
	private BlackBoxWorker bbWork;
	private bool running;
	
	public myProcessor() {
		bbWork = new BlackBoxWorker();
	}

	public void Starting() {
		running = true;
		while(running) {
			bbWork.Work(); 		// This is blocking the whole Thread for some time
			Thread.Sleep(5000);
		}
	}

	public void Stopping() {
		running = false;
	}
}

Class Application
{
	static void main (args)
	{
		myProcessor mP = new myProcessor();
		
		// doing work here ....
		
		// myProcessor im background starten ....
		// aber wie ?
		// Thread.Start(mP.Starting)
		
		// doing work here
		
		// myProcessor im background stopen ....
		// aber wie ?
		// Thread.Start(mP.Stopping)
		
	}
}

C
2.121 Beiträge seit 2010
vor 10 Jahren

Klappt nicht mehr bedeutet was genau?

Thread.Start(mP.Starting)

Guck dir an wie man Threads anlegt.

Die Stopmethode brauchst du nicht in einen Thread packen. Das wäre ein anderer Thread als der in dem Starting läuft. Für das Setzen des Merkers brauchst du keinen extra Thread.
Du solltest "running" als volatile deklarieren (-> siehe Hilfe).

Noch ein bisschen Klugscheiß zum Schluss, ich würds nur Start und Stop nennen, ohne ing hinten dran 😃

61 Beiträge seit 2009
vor 10 Jahren

Ich denke, ich verstehe in etwa worum es geht.

Für ein sauberes Threading muss man festlegen, wie der Thread laufen soll und wie er gestoppt werden darf.

Es ist nicht ohne Weiteres möglich (es gibt schon Methoden, aber die würde ich nicht empfehlen) einen Thread zu stoppen, wenn die Methode, die ausgeführt wird selbst nicht überprüft, ob sie ihre Arbeit abbrechen muss oder weitermachen kann.

Grundsätzlich kann der Thread in deinem Fall in der Klasse myProcessor erstellt werden und über Abort beendet werden.
Denn Abbruch über Abort zu machen, wäre jedoch nicht sehr klug, da dies ungeahnte Folgen haben kann.
Zum einen wird eine ThreadAbortException im laufenden Thread ausgelöst und zum anderen kann man nicht bestimmen wo genau der Abbruch stattfinden soll.

Dann würde das wie folgt aussehen:


Class myProcessor
{
    private BlackBoxWorker bbWork;
    private bool running;
    private Thread myThread;

    public myProcessor() {
        bbWork = new BlackBoxWorker();
    }

    public void Starting() {
        myThread = new Thread(bbWork.Work);
        myThread.Start();
        running = true;
    }

    public void Stopping() {
        if (running) {
            myThread.Abort();
        }
        running = false;
    }
}

Um aber eine geeignete Methode zu finden, muss natürlich klar sein wie in diesem Beispiel der BlackBoxWorker seine Arbeit im Hintergrund ausführen soll.
Die Verwendung einer while-Schleife und das Prüfen des Parameters running deutet für mich darauf hin, dass die Arbeit in der Work-Methode immer vollständig abgeschlossen werden muss und dann wiederholt werden soll.
Sehe ich das richtig?

Solche grundsätzlichen Formulierungen sind wichtig, damit auch hilfreiche Antworten gegeben werden können 😉

Ich gehe daher einmal von folgender Sachlage aus:
Es gibt die Klasse BlackBoxWorker.
Diese Klasse besitzt die Methode Work.
Die Methode Work erledigt bestimmte Aufgaben, die vollständig ausgeführt werden müssen.
Wenn die Arbeit abgeschlossen wurde, soll dieser Schritt wiederholt werden, sofern kein "Stop" (Abbruch) signalisiert wurde.

Wenn dies das Ziel ist, dann könnte die Lösung auch wie folgt aussehen:


class myProcessor
{
    private BlackBoxWorker bbWork;
    private bool running;           // Wird vom Thread festgelegt; zur Prüfung ob der Thread beendet wurde
    private bool doAgain;           // Wird vom Thread beim Start festgelegt; zur Angabe, ob die Arbeit wiederholt werden soll
    private Thread myThread;

    public myProcessor() {
        bbWork = new BlackBoxWorker();
    }

    public void Starting() {
        if(running) return;

        myThread = new Thread(this.Worker);
        myThread.Start();            
    }

    private void Worker() {
        running = true;
        doAgain = true;

        while(doAgain) {
            bbWork.Work();         // This is blocking the whole Thread for some time
            Thread.Sleep(5000);
        }

        running = false;
    }


    public void Stopping() {
        if(!running) return;

        doAgain = false;
        myThread.Join();            // (optional) wartet auf den Abschluss des Threads
    }
}

class Application
{
    static void main (args)
    {
        myProcessor mP = new myProcessor();

        // doing work here ....

        // myProcessor im background starten ....
        // aber wie ?
        mP.Starting();

        // doing work here

        // myProcessor im background stopen ....
        // aber wie ?
        mP.Stopping();

    }
}

Vielleicht konnte ich ja doch helfen 🙂

In der Zeit vor fünf Minuten ist Jetzt die Zukunft. Jetzt ist die Gegenwart. Die Zeit, in der ich zu erzählen begonnen habe, ist die Vergangenheit von Jetzt und die Zukunft von der Gegenwart der Zeit, fünf Minuten bevor ich zu erzählen begann.

16.806 Beiträge seit 2008
vor 10 Jahren

Ab .NET 4.0 wäre es mit Task Cancellation deutlich einfacher, übrsichtlicher und sicherer.

49.485 Beiträge seit 2005
vor 10 Jahren

Hallo JMano,

man kann eine Klasse nicht als ganzes in einen anderen Thread verlagern. Es ist nicht die Klasse, die in einem (anderen) Thread läuft, sondern der Code einer Methode wird immer von dem Thread ausgeführt, der die Methode aufgerufen hat. Solange ein Thread eine Methode kennt, kann er sie auch aufrufen und dann führt er selbst deren Code aus. Tun das mehrere Thread (potenziell) gleichzeitig, muss die Methode (bzw. ggf. die ganze Klasse) thread-safe geschrieben sein.

Natürlich gibt es Mittel, um die Ausführung von einem Thread in einen anderen Thread zu verlagern, aber nur, wenn beide Thread für diese Zusammenarbeit programmiert sind.

Wenn man einzelne Arbeitsaufträge in einen anderen Thread verlagern möchte, kann man z.B. die SyncQueue <T> - Eine praktische Job-Queue bzw. die darin genannten Alternativen verwenden.

herbivore

J
JMano Themenstarter:in
38 Beiträge seit 2013
vor 10 Jahren

Wow, danke für die vielen Antworten.

Mir gefällt Rubens Ansatz (schön einfach) am besten.

Nur das ich ein Problem bei dem ganzen übersehen habe:
Der bbWork.Work(); kann auch mehrere Minuten (oder Stunden) blockieren ...
Er verarbeitet irgendwelche Netzwerk anfragen.
Ich habe mal den Ersteller (alter Kollege) angeschrieben, ober nicht doch den Quell Code irgendwo hat, um drinnen zu schauen was da passiert.

Habe jetzt versucht den Thread dann mit myThread.Abort() abzubrechen ... allerdings hat das keine Wirkung gezeigt ...
Denke, dass es bei Task Cancellation ähnlich sein wird. Muss ich mir aber noch ansehen ...

49.485 Beiträge seit 2005
vor 10 Jahren

Hallo JMano,

Task Cancellation funktioniert nur, wenn der zu cancelnde Thread kooperativ ist, also von sich aus die Cancel-Variable abfragt und sich dann selbst beendet. Nach dem, was du schreibst, wird das wohl nicht der Fall sein.

herbivore

H
114 Beiträge seit 2007
vor 10 Jahren

Hallo JMano,

Ich habe mal den Ersteller (alter Kollege) angeschrieben, ober nicht doch den Quell Code irgendwo hat, um drinnen zu schauen was da passiert.

als kleiner Hinweis. Du kannst auch selber in einer DLL nachschauen, was da konkret passiert. Dazu gibt es sogenannte Decompiler (z.B. ILSpy, dotPeek, etc.).
Nutze ich auch gern mal, wenn ich einfach wissen möchte, was konkret in einer Methode passiert und ich den Sourcecode eben nicht vorliegen hab. Bietet sich auch bei Klassen des .NET-Frameworks immer mal wieder an (auch wenn mir bewusst ist, dass man diese sogar via Visual Studio debuggen kann, aber meist reicht mir ein Blick).

Grüße, HiGHteK