PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [C#] Wie Anwendung am Terminieren hindern (bzw. am besten idlen lassen)?


minos5000
2008-08-21, 15:58:57
Hi,

ich bastel gerade an einer Anwendung die später auf einem Handy laufen soll und ich will mit den Ressourcen möglichst schonend umgehen.

Die Anwendung realisiert ein Observer Pattern bei dem in unregelmäßigen Abständen verschiedene Funktionen aufgerufen werden und wann immer eine dieser Funktionen aufgerufen wird, soll die, ich sag mal Hauptklasse der Anwendung, darüber informiert werden.

Bisher verwende ich einen Thread in einer Endlosschleife, der einfach vor sich hin läuft, damit die Anwendung nicht terminiert. Aber ich habe das dumpfe Gefühl, dass es auch effizienter gehen müsste, denn wenn die Anwendung im Hintergrund läuft verhält sich das Gerät träger als sonst.


Ich habe beim Googeln ein Beispiel gefunden, wo anscheinend jemand GC.KeepAlive() verwendet, um die Anwendung am terminieren zu hindern. Wäre das auch hier eine Option?


Hier mal der Code, der die Anwendung anstößt und sich um das warten kümmert. Die "Update" Methode wird vom observed Subject immer dann aufgerufen, wenn eine dessen Funktionen aufgerufen wurde.



static class Program
{

static void Main()
{
Engine engine = new Engine();
}
}

class Engine : Observer
{
private Logger logger;
private PositionProvider pp;
private Thread t;
private bool running;

public Engine()
{
SDResult result;
this.logger = new Logger();
pp = new PositionProvider(logger);
pp.Observer = this;
result = pp.Startup();
logger.log("Result: " + result.ToString());
running = true;
t = new Thread(HappyWaiting);
t.Start();
}

public void Update(String s)
{
logger.log("Update called");
logger.log(s);
if (s == "update")
{
logger.log("Latitude: " + pp.Latitude);
logger.log("Longitude: " + pp.Longitude);
}
if (s == "shutdown")
{
running = false;
logger.log("running = false");
}
}

private void HappyWaiting()
{
logger.log("HappyWaiting called");
while (running)
{
Thread.Sleep(1000);
}
}
}



vg
minos

Monger
2008-08-21, 16:20:52
Ein Thread.Sleep ist relativ teuer. So muss der Thread nämlich immer noch in jeder Zeitscheibe überwacht werden, ob er denn noch schlafen soll, oder besser aufwachen soll.

Schau dir mal die Timer Klasse an. Gibt zwei Varianten davon: einer für die Windows Forms, und einen für Dienste wie wohl deinen. Der dreht den Spieß rum: der meldet sich nur dann, wenn ein bestimmtes Zeitereignis eintritt. Das ist vergleichsweise ressourcenschonend.

minos5000
2008-08-21, 16:32:12
Daran dachte ich auch schon, aber da ich gegen ein Handy programmiere muss ich das Compact Framework programmieren und dort wird kein System.Timers unterstützt. Nur im Zusammenhang mit Forms.

Monger
2008-08-21, 17:28:24
Es gibt noch einen dritten Timer Typ - vielleicht hilft der dir weiter:

http://msdn.microsoft.com/en-us/library/system.threading.timer.aspx

Du musst dann natürlich immer noch verhindern, dass dein Programm terminiert wird - sonst verliert das Hauptprogramm die Referenz zum Timer, und der Garbage Collector sammelt alles ein.

Da dein Programm ja offenbar so eine Art Dienst ist, wäre es vielleicht klug, es auch als richtigen Dienst zu registrieren.
Visual Studio bietet beim Start als Projekttyp auch eine Dienstanwendung an.

minos5000
2008-08-21, 18:13:35
Der dritte Typ sieht eigentlich ganz gut aus, und ich hätte auch eine Idee, wie ich es mit dem realisieren könnte, aber das doofe ist, dass TimerCallback anscheinend ein Objekt und keine Methode erwartet.
Ich glaub ich such noch etwas, bevor ich den Code dahingehend umbaue.

Und einen Dienst daraus machen, ich denke beim Compact Framework geht das nicht. Zumindest hab ich keine Möglichkeit dazu gefunden.

robobimbo
2008-08-21, 22:51:29
Schau mal ob nicht das was für dich ist, bzw. ob da was dabei ist dass du brauchen kannst:

Sind noch jede Menge andere Vids über Devices dabei btw. [edith says] http://msdn.microsoft.com/en-us/netframework/bb495180.aspx [/edith says]

http://msdn.microsoft.com/de-at/netframework/cc761483(en-us).aspx

How Do I: Monitor for an Application to Exit Without Draining the Device Battery?

minos5000
2008-08-22, 15:01:23
Der Link sieht sehr gut aus, werd mir das Video gleich ansehen.

Ich bin inzwischen auch auf etwas anderes gestoßen, mit dem unter dem Compact Framework Windows artige Dienste realisieren kann.

http://www.codeplex.com/managedserviceswm

Bietchiebatchie
2008-08-23, 00:36:42
Der dritte Typ sieht eigentlich ganz gut aus, und ich hätte auch eine Idee, wie ich es mit dem realisieren könnte, aber das doofe ist, dass TimerCallback anscheinend ein Objekt und keine Methode erwartet.
Das passt schon: Die Timer-Klasse erwartet einTimerCallback - das ist ein Delegate (d.h. eine Methoden/Funktionssignatur) vom Typ object -> void.

Aber eigentlich willst du das gar nicht nutzen glaube ich, die Klasse dir am meisten helfen sollte ist System.Threading.AutoResetEvent (http://msdn.microsoft.com/en-us/library/system.threading.autoresetevent(VS.71).aspx).

Desweitern ist es (meiner Meinung nach) ziemlich unsinnig das Observer-Pattern in C# zu implementieren - das ist nämlich schon in die Sprache eingebaut ;) Mit Events können Klasse extrem simpel andere Klassen über ihren Zustand/ihre aktuelle Tätigkeit informieren:

In deinem Fall könnte man das z.B. so machen:


// Ich weiß nicht was der PositionProvider genau machen soll, deshlab rate ich einfach mal und behaupte er in bestimmten Abständen neue Positionen liefern.
public class PositionProvider
{
public void Run()
{
//...

OnNewPosition(new EventArgs());
}

public event EventHandler NewPosition;
public event EventHandler Completed;

protected virtual void OnNewPosition(EventArgs e)
{
if (this.NewPosition != null)
this.NewPosition(this, e);
}

protected virtual void OnCompleted(EventArgs e)
{
if (this.Completed != null)
this.Completed(this, e);
}
}

public class Engine
{
public void Run()
{
Thread thread = new Thread(PositionProviderRun);
thread.Start();
this.resetEvent.WaitOne();
}

private void PositionProviderRun()
{
PositionProvider positionProvider = new PositionProvider();
positionProvider.Completed += (sender, eventArgs) => this.resetEvent.Set();
positionProvider.NewPosition += (sender, eventArgs) => { /* was auch immer: loggen,... */ };
}

private AutoResetEvent resetEvent = new AutoResetEvent(false);
}


Man sieht zwei Sachen:
- durch das NewPosition-Eventskann der PositionProvider die Engine über ihren Zustand informieren ohne dass der PositionProvider irgendwas über die Engine weiß
- durch das CompletedEvent in Kombination mit dem ResetEvent kann dem erstellenden Thread signalisiert werden dass er weiterlaufen (bzw. ein dem Fall sich beenden) kann.
Ich weiß jetzt allerdings nicht inwiefern dich das weiterbringt :)

minos5000
2008-08-23, 09:52:44
Danke für den Tipp, ich werds auf jeden Fall mal ausprobieren.

Ich hatte vorher auch etwas mit dem ManualResetEvent rumgespielt, aber aus mir nicht bekannten Gründen hatte der Ablauf bei .waitOne nie angehalten und ich hab's nicht weiter verfolgt.