Laden...

Method Interrupt

Erstellt von rollerfreak2 vor 13 Jahren Letzter Beitrag vor 13 Jahren 2.671 Views
rollerfreak2 Themenstarter:in
916 Beiträge seit 2008
vor 13 Jahren
Method Interrupt

Hallo zusammen, ich beschreibe erstmal die Randbedingungen. Eine Methode berechnet einen Modus an einer verbunden Peripherie. Diese Berechnung erfordert eine "Pause" die dynamisch ist, daher berechnet wird. Sprich die Methode fragt einige Dinge an, muss dann kurz pausieren (das kann man leider nicht Ändern, das ist ein MUSS), und fragt dann noch ein paar dinge ab. Anschließend hat die Methode alle nötigen Daten um den Modus zu berechnen.

Die Methode hängt an einem Service welcher im GUI Thread erzeugt wurde. Nun gibt es 2 Möglichkeiten den Modus anzufragen. Zum einen Synchron, daher direkt. Zum anderen asynchron, daher im Service selber wird die Methode in einem separaten Thread ausgeführt. Ist der Thread beendet, wird dem Caller der Asynchronen Methode via Callback bescheid gegeben, das dass Ergebnis des Modus nun vorliegt.

Wird die Async Methode ausgeführt, so gibt es noch die Möglichkeit den Berechnung abzubrechen. Dazu wird einfach eine boolsche Variable gesetzt, welche im Thread immer wieder abgefragt wird, und im falle diese ist true, wird via return die Methode die dem Thread zugeteilt ist verlassen und damit die Berechnung beendet.

Mir geht es jetzt um das Design des Interrupts. Klingt vielleicht einfach, jedoch gibt es da wie immer mehrere Ansätze. Mir fallen Spontan 3 Stück ein. Die GetModi Methode liefert den Modus. Diese kann entweder direkt gerufen werden, oder über einen separaten Thread. Daher muss die GetModi() Methode immer wieder das oben genannte bool abfragen (volatile aborted).


Modi GetModi()
{
    ....
    if (aborted) return Modi.Aborted;
    ....
    if (aborted) return Modi.Aborted;
    ....
    //here we need the timer interrupt for example 4000 ms
    //we could not ask for the aborted flag during the interrupt
    Thread.Sleep(4000);
    ....
    if (aborted) return Modi.Aborted;
    ....
}


Modi GetModi()
{
    ....
    if (aborted) return Modi.Aborted;
    ....
    if (aborted) return Modi.Aborted;
    ....
    //here we need the timer interrupt for example 4000 ms
    Timer t = new Timer(4000);
    this.m_interruptReached = false;
    t.Elapsed += this.Elapsed;
    t.Start();
    while (!this.m_interruptReached)
    {
        //polling... 
        if (aborted) return Modi.Aborted;
    }
    t.Stop();

    ....
    if (aborted) return Modi.Aborted;
    ....
}

void Elapsed(object sender, EventArgs args)
{
    this.m_interruptReached = true;
}


Modi GetModi()
{
    ....
    if (aborted) return Modi.Aborted;
    ....
    if (aborted) return Modi.Aborted;
    ....
    //here we need the timer interrupt for example 4000 ms
    //we could ask for the aborted flag between the time interrupt
    for (int i = 0; i < 8; ++i)
    {
        Thread.Sleep(500);
        if (aborted) return Modi.Aborted;
    }
    ....
    if (aborted) return Modi.Aborted;
    ....
}

Ich weis, Thread.Sleep ist nicht schön, jedoch hätte es den Vorteil, das während des Sleeps ein anderer Thread die CPU Power bekommt, das wäre im 2ten Beispiel nicht der Fall (Polling). Gibt es für solche UseCases ein Design Pattern, mir ist dafür leider keines bekannt. Was sagt Ihr dazu, wie würdet ihr das Designen mit den gegebenen Vorgaben?

Again what learned...

6.911 Beiträge seit 2009
vor 13 Jahren

Hallo,

Die Methode hängt an einem Service welcher im GUI Thread erzeugt wurde.

Die UI sollte nie warten, denn sonst friert sie ein.

Eine Methode berechnet einen Modus an einer verbunden Peripherie. Diese Berechnung erfordert eine "Pause" die dynamisch ist, daher berechnet wird. Sprich die Methode fragt einige Dinge an, muss dann kurz pausieren (das kann man leider nicht Ändern, das ist ein MUSS), und fragt dann noch ein paar dinge ab.

Ich würde das über 2 Threads lösen die mit den Methoden der Monitor-Klasse synchronisiert/gepulst werden. Wie das gehts zeigt zB SyncQueue <T> - Eine praktische Job-Queue sehr schön.

Wie wird übrigens die Pause berechnet?

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

rollerfreak2 Themenstarter:in
916 Beiträge seit 2008
vor 13 Jahren

Hallo,

Wie wird übrigens die Pause berechnet?

Das ist von einigen Dingen der Peripherie abhängig, das kann/darf ich hier nicht genauer erklären. Wichtig ist, im normal falle sind die Interrupts/pausen im Millisekunden Bereich, 300-800ms. Von daher friert die GUI nicht gleich ein.

Die UI sollte nie warten, denn sonst friert sie ein.

Da hast du eigentlich recht, nur folgende Randbedingung sind einzuhalten. Die Methode integriert sich in ein Framework welches die Methode auch synchron aufruft, daher erwartest es auch das Ergebnis synchron. Dem entsprechend kann ich dort den Aufruf leider nicht beeinflussen.

Again what learned...

3.971 Beiträge seit 2006
vor 13 Jahren

Die Methode integriert sich in ein Framework welches die Methode auch synchron aufruft, daher erwartest es auch das Ergebnis synchron. Dem entsprechend kann ich dort den Aufruf leider nicht beeinflussen.

Aber du kannst die Gui logisch von deinem Framework/BusinessClass trennen - Ist kein muss, nur sind die Anwender von heute sehr verwöhnt.

Alternative zu Thread.Sleep ist ein Timer.

Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...

6.911 Beiträge seit 2009
vor 13 Jahren

Hallo,

du musst ja nicht detailliert erklären wie die Pause berechnet wird. Das sollte eh separat erfolgen. Von daher frag ich anders: Wie bekommt die GetModi-Methode den Wert für die Pause mitgeteilt? Ohne das zu wissen kann auch kein vernüftiger Vorschlag gegeben werden.

Auch wenn es Vorgabe ist das synchron aufzurufen kann die Ausfürhung nebenläufig erfolgen. Das "Ergebnis-Event" muss dann halt mit dem UI-Thread synchronisiert werden.

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

rollerfreak2 Themenstarter:in
916 Beiträge seit 2008
vor 13 Jahren

Alternative zu Thread.Sleep ist ein Timer.

Die 2 Vorschläge habe oben schon aufgeführt. Nur welcher ist besser?

Wie bekommt die GetModi-Methode den Wert für die Pause mitgeteilt?

Die GetModi Methode berechnet die Pause anhand von Daten die es im GetModi von der Peripherie bekommt.

Auch wenn es Vorgabe ist das synchron aufzurufen kann die Ausfürhung nebenläufig erfolgen.

Ich denke das geht nicht, weil den Aufruf kann ich nicht beeinflussen. Daher derjenige der mich ruft erwartet das Ergebnis im Return Value der Methode. Daran kann man leider nix Ändern, sprich über ein Event synchronisieren ist leider nicht möglich.

Again what learned...

6.911 Beiträge seit 2009
vor 13 Jahren

Hallo,

kannst du das vorgegeben Umfeld mal kurz skizzieren? Also was ist gegeben und kann / kann nicht geändert werden.

Wäre folgendes möglich?


Modi GetModi()
{
	// fragt einige Dinge an

	// Berechnung der Dauer der Pause
	int pauseTime = 100;
	Modi modus = null;

	using (ManualResetEventSlim mre = new ManualResetEventSlim())
	using (Timer timer = new Timer(
		_ =>
		{
			// Berechnung des Modus
			modus = BerechneModus();

			mre.Set();
		},
		null,
		pauseTime,
		Timeout.Infinite))
	{
		mre.Wait();
	}

	return modus;
}

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

49.485 Beiträge seit 2005
vor 13 Jahren

Hallo rollerfreak2,

wenn man in einem Vorgang eine bestimmte Zeitspanne warten will, den Vorgang aber auch während dieser Zeitspanne abbrechen können will, bietet es sich an, die Sache gedanklich umzudrehen, also vorrangig auf den Abbruch zu warten, aber das maximal eine bestimmte Zeitspanne lang, sprich z.B. einen AutoResetEvent mit TimeOut zu verwenden. Damit vermeidet man jede Art von Polling und trotzdem (oder gerade deshalb) wird ein Abbruch verzögerungsfrei behandelt. Also weder Timer noch Thread.Sleep sind hier optimal.

herbivore

6.911 Beiträge seit 2009
vor 13 Jahren

Hallo,

welche .net-Version verwendest du?
Für .net 4.0 gibts mit Cancellation elegante Möglichkeiten um das von herbivore vorgeschlagene umzusetzen. Schau dir dann auch das PDF aus Patterns for Parallel Programming with the .NET Framework an - ich denke der Abschnitt (bzw. das Stichwort für die Suche im Dokumnet) "For the future" könnte passend sein.

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

rollerfreak2 Themenstarter:in
916 Beiträge seit 2008
vor 13 Jahren

welche .net-Version verwendest du?

Wir sind leider auf 2.0 beschränkt! Das von herbivore vorgeschlagene klingt zwar gut, löst aber das Problem des Wartens nicht, oder ich hab es nicht richtig verstanden. Also die Methode GetModi soll zu jeder Zeit abbrechenbar sein! Desweiteren soll die Methode an einer bestimmten Stelle im Code eine bestimmte Zeit warten, ohne jedoch die Methode zu verlassen.

Das mit dem AutoResetEvent schau ich mir mal an. Wer raised das denn, und wie beende ich dann die Methode? Und was hat das mit der von mir erwähnten Pause zu gemeinsam?

Again what learned...

49.485 Beiträge seit 2005
vor 13 Jahren

Hallo rollerfreak2,

Das von herbivore vorgeschlagene klingt zwar gut, löst aber das Problem des Wartens nicht, oder ich hab es nicht richtig verstanden. Also die Methode GetModi soll zu jeder Zeit abbrechenbar sein!

doch, genau das wird mit meinem Vorschlag erreicht.

Das mit dem AutoResetEvent schau ich mir mal an. Wer raised das denn, und wie beende ich dann die Methode?

Die Methode, die aufgerufen wird, um die Aktion abzubrechen. Eine (volatile) boolsche Variable brauchst du natürlich weiterhin.

herbivore

rollerfreak2 Themenstarter:in
916 Beiträge seit 2008
vor 13 Jahren

Okay das mit dem abbrechen das habe ich verstanden. Wie aber soll ich damit die "Pause" erreichen? Kannst du das bitte noch mal ein bisschen genauer Erklären?

Again what learned...

49.485 Beiträge seit 2005
vor 13 Jahren

Hallo rollerfreak2,

durch den Timeout. Also ich finde das alles sehr offensichtlich und ärgere mich ehrlich gesagt etwas über die in meinen Augen überflüssigen Nachfragen. Das Prinzip habe ich beschrieben und alles weitere kannst du der Doku entnehmen.

herbivore

rollerfreak2 Themenstarter:in
916 Beiträge seit 2008
vor 13 Jahren

Hallo herbivore,

ich finde das überhaupt nicht offensichtlich. Desweiteren "denke" ich das ich falsch verstanden wurde.

wenn man in einem Vorgang eine bestimmte Zeitspanne warten will, den Vorgang aber auch während dieser Zeitspanne abbrechen können will...

Das Wort während ist falsch, es ist zu jedem Zeitpunkt der Ausführung möglich die GetModi Mehtode abzubrechen. Ich glaube unten stehendes Diagramm verdeutlicht das was ich erreichen will etwas. Nehmen wir mal nur die Sync methode, diese kann auch nicht abgebrochen werden! Den Aufruf der GetModi sync findet im GUI Thread statt. Laut deiner Aussage ist das pollen dort nicht mehr notwendig wenn man die Denkweise umdreht.

den Vorgang aber auch während dieser Zeitspanne abbrechen können will, bietet es sich an, die Sache gedanklich umzudrehen, also vorrangig auf den Abbruch zu warten, aber das maximal eine bestimmte Zeitspanne lang, sprich z.B. einen AutoResetEvent mit TimeOut zu verwenden. Damit vermeidet man jede Art von Polling

Leider hab ich keinen Plan wie das gehen soll, wenn man in der im Diagramm dargestellten Methode eine Pause machen soll, ohne zu pollen?

Again what learned...

6.911 Beiträge seit 2009
vor 13 Jahren

Hallo,

zeichnen im Bild noch ein wo überall abgebrochen werden kann. So wie das Bild jetzt da ist wärs genau mein obiger Code.

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

rollerfreak2 Themenstarter:in
916 Beiträge seit 2008
vor 13 Jahren

So wie das Bild jetzt da ist wärs genau mein obiger Code.

Welchen obigen Code meinst du denn? Wenn du den Task<TResult> meinst, im PDF unter for the future, den Task kann ich nicht verwenden => .NET 2.0.

Das unterbrechen der Methode durch den User kann nur erfolgen, wenn die Methode Async aufgerufen wird. Das unten stehende Diagramm zeigt den Async aufruf. Dort kann die Methode zu jeder Zeit beendet werden. Daher immer dann wenn das aborted flag gesetzt wird soll der Thread beendet werden.

Again what learned...

6.911 Beiträge seit 2009
vor 13 Jahren

Hallo,

Welchen obigen Code meinst du denn?

Es gibt eh nur einen der bisher gepostet wurde und nicht von dir ist 😉
Aber da kannst du gleich Thread.Sleep nehmen, denn mehr macht obiger Code bei genauer Betrachtung auch nicht wirklich.

Der Unterschied zu herbivores Vorschlag oben ist also dass jederzeit abgebrochen werden soll und nicht während des Wartens. Korrekt?

Die Bilder hättest du eingangs posten könne dann wärs gleich klarer gewesen 😉
Da du schreibst dass die async Methode gleich der sync Methode ist und ein Callback mitgegeben wird kann die Implementierung für beide gleich sein und der async Aufruf geht über Delegate.BeginInvoke - dort auch das Callbakc angegeben.

Ist es möglich das Abbrechen so handzuhaben dass beim Abbruch die asynchrone Ausführung normal zu Ende läuft aber dessen Ergebnis (sprich das Callback) ignoriert / nicht verwendet wird?
Oder wenns möglich ist dass am Ende der Methode 1x geprüft wird ob abgebrochen wird oder nicht und dann entsprechend der Callback aufgerufen wird oder nicht. Dabei wären aber wieder die sync und async nicht ganz gleich bzw. der Delegat für den async-Aufruf müsste angepasst werden.
Sonst ist ein Abbruch eines Threads aus dem ThreadPool nicht möglich* - ich meine wirklich Abbruch. Das ginge nur sehr unsauber über Thread.Abort aber das sollte wenn schon nur für selbst erstellte Threads verwendet werden, und nicht mal dort.

* auch wenn du vor und nach jedem Metodenaufruf ein (volatile) bool prüfst wäre das nicht jederzeit - wenn man es genau nimmt.

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

rollerfreak2 Themenstarter:in
916 Beiträge seit 2008
vor 13 Jahren

Es gibt eh nur einen der bisher gepostet wurde und nicht von dir ist 😉

Sorry, den hab ich übersehen 😄

Der Unterschied zu herbivores Vorschlag oben ist also dass jederzeit abgebrochen werden soll und nicht während des Wartens. Korrekt?

So ist es aber das habe ich auch eingangs auch erwähnt und so geht es eigentlich auch aus dem ersten Code Post heraus dachte ich. Die Bilder hätte ich gleich anfangs schon mit posten können, das wäre sicher eleganter gewesen.

Ist es möglich das Abbrechen so handzuhaben dass beim Abbruch die asynchrone Ausführung normal zu Ende läuft aber dessen Ergebnis (sprich das Callback) ignoriert / nicht verwendet wird?

Nein das ist leider nicht möglich, weil der Service Disposed wird, daher soll auch der Thread "sofort", bzw. ziemlich bald beendet werden, damit der Service dispose aufruf zurück zum Aufrufer kehrt.

* auch wenn du vor und nach jedem Metodenaufruf ein (volatile) bool prüfst wäre das nicht jederzeit - wenn man es genau nimmt

Das ist mir klar, jedoch ist das besser, als am Thread.Abort aufzurufen.

Fazit, ob Timer oder Thread.Sleep ist eigentlich Schnuppe. Beim Thread.Sleep wird halt nicht gepolled.

Again what learned...

49.485 Beiträge seit 2005
vor 13 Jahren

Hallo rollerfreak2,

ich verstehe überhaupt nicht, was du an meinem Vorschlag nicht verstehst. Natürlich löst der dein Problem.

wenn man in einem Vorgang eine bestimmte Zeitspanne warten will, den Vorgang aber auch während dieser Zeitspanne abbrechen können will...

Wie du einen Thread abbrechen kannst, weißt du doch, nämlich mit einer (volatilen) boolschen Variable. Deshalb habe ich dazu nichts geschrieben. Dein Problem war jetzt, wie man auch während einer "Pause" abbrechen kann. Wie wie man die Pause realisiert und bei Bedarf abbrechen kann, habe ich beschrieben. Das kombiniert mit der (volatilen) boolschen Variable (direkt hinter der Pause sowie an allen anderen Stellen wo du es sowieso schon hattest), löst dein Problem. Ich verstehe nicht, was daran unverständlich sein soll, zumindest nachdem ich gesagt habe, dass du die (volatile) boolsche Variable natürlich weiterhin brauchst. Und wie schon gesagt, weder Timer noch Thread.Sleep sind hier angebracht.

herbivore

rollerfreak2 Themenstarter:in
916 Beiträge seit 2008
vor 13 Jahren

Hallo herbivore,

ich glaub jetzt hab ich verstanden wie das von dir Beschreibende Prinzip funktioniert. Zum einen bleibt die boolsche Variable bestehen, die zum beendet verwendet wird. Die kann nur gesetzt werden wenn die GetModi Methode in einem Thread ausgeführt wird, daher Async. Und nun einfach die Logik herum drehen, einfach ein WaitOne zu rufen, und im Falle die Methode soll abgebrochen werden, die boolsche Variable setzen und am AutoResetEvent Set aufrufen.


private void GetModiAsync()
{
    //this method is executed in a separat thread
    ...
    if (this.m_aborted) return;
    ...
    if (this.m_aborted) return;
    ...
    this.m_autoResetEvent.WaitOne(interruptTime);
    this.m_autoResetEvent.Reset();
    ...
    if (this.m_aborted) return;
    ...
}

public void ThreadAbord()
{
    this.m_aborted = true;
    //force the thread to stop the interrupt
    this.m_m_autoResetEvent.Set();
}

Hat zwar lang gedauert bis ich es kapiert habe, aber besser später als nie 😄

Danke für den echt hilfreichen Ansatz.

Again what learned...

6.911 Beiträge seit 2009
vor 13 Jahren

Hallo,

beim AutoResetEvent ist ein Aufruf von Reset nicht notwendig denn das passiert Auto im Gegensatz zum ManualResetEvent.

Den Code für GetModiSync und Async könntest du dann noch in eine Methode auslagern und per Flag mitteilen ob sync/async ist und dann halt nicht auf das WaitHandle warten oder eben doch. DRY.

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

rollerfreak2 Themenstarter:in
916 Beiträge seit 2008
vor 13 Jahren

beim AutoResetEvent ist ein Aufruf von Reset nicht notwendig denn das passiert Auto im Gegensatz zum ManualResetEvent.

Hab ich auch grad gesehen, das wird beim Aufruf von WaitOne automatisch gesetzt.

Den Code für GetModiSync und Async könntest du dann noch in eine Methode auslagern und per Flag mitteilen ob sync/async ist und dann halt nicht auf das WaitHandle warten oder eben doch

Der Interrupt muss IMMER sein, daher sowohl bei Sync als auch bei Async!

Again what learned...

6.911 Beiträge seit 2009
vor 13 Jahren

Hallo,

hab mich vertan. Meinte das Abbrechen -> if (async && m_aborted)

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

rollerfreak2 Themenstarter:in
916 Beiträge seit 2008
vor 13 Jahren

Hallo,

die Abfrage nach if (async && m_aborted) ist unnütz. Das m_aborted flag ist im Sync Falle sowieso immer auf false. Und im Async Fall ist es halt entweder false, oder true. Von daher ist die "zusätzliche" abfrage nach dem sync/async flag nicht notwendig bzw. überflüssig.

Again what learned...