2009-03-11 10 views
13

In seiner article about preventing multiple instances einer Anwendung verwendet wird, stellt Michael Covington diesen Code:GC.KeepAlive gegen

static void Main()     // args are OK here, of course 
{ 
    bool ok; 
    m = new System.Threading.Mutex(true, "YourNameHere", out ok); 

    if (! ok) 
    { 
     MessageBox.Show("Another instance is already running."); 
     return; 
    } 

    Application.Run(new Form1()); // or whatever was there 

    GC.KeepAlive(m);    // important! 
} 

Er erklärt, dass die GC.KeepAlive (m) erforderlich, um den Garbage Collector von der Erhebung der Mutex früh zu verhindern , da es keine zusätzlichen Hinweise darauf gibt.

Meine Frage: wickelt der Mutex in einer Verwendung die gleiche Sache? Das heißt, wird das Folgende auch verhindern, dass der GC den Teppich unter mir wegzieht?

static void Main()     // args are OK here, of course 
{ 
    bool ok; 
    using (var m = new System.Threading.Mutex(true, "YourNameHere", out ok)) 
    { 
     if (! ok) 
     { 
      MessageBox.Show("Another instance is already running."); 
      return; 
     } 

     Application.Run(new Form1()); // or whatever was there 
    } 
} 

Mein Bauchgefühl ist, dass das funktioniert verwenden, da die Verwendung ist (sein soll) entspricht:

Mutex m = new System.Threading.Mutex(true, "YourNameHere", out ok); 
try 
{ 
    // do stuff here 
} 
finally 
{ 
    m.Close(); 
} 

Und ich würde denken, dass die m.Close() es ausreichen würde, um dem JIT-Compiler zu signalisieren, dass es eine weitere Referenz gibt, wodurch eine vorzeitige Speicherbereinigung verhindert wird.

+0

Ich bin kein CLR-Experte (weshalb ich keine Antwort hinzufügen), aber es scheint mir, dass das, was Sie tun, sollte funktionieren. Ich sage es ausprobieren und sehen. –

+4

Wenn man über den GC spricht, ist "ausprobieren und sehen" eine schlechte Idee. Ich hatte Fälle, in denen Tests sagten, dass es funktionieren sollte, aber es scheiterte in der Produktion. Vieles hat mit dem Unterschied zu tun, wie der JIT-Compiler im Release-Debug-Modus arbeitet. –

Antwort

17

den Mutex in einem using Aussage Wrapping wird es in der Tat verhindern, dass Müll gesammelt, wird aber auch entsorgen sie (es nennt Dispose, nicht Close) am Ende (während GC.KeepAlive wird nicht, natürlich).

Wenn das Ende der Methode wirklich das Ende des Prozesses sein wird, glaube ich nicht, dass es wahrscheinlich einen praktischen Unterschied machen wird, den Sie verwenden - ich bevorzuge die using Aussage über den allgemeinen Grundsatz der Entsorgung von irgendetwas welche implementiert IDisposable.

Wenn der Mutex beim Beenden des Prozesses nicht entsorgt wurde, wird der Finalizer sich darum kümmern, solange andere Finalisierer den Finalisierungs-Thread nicht über den Timeout hinaus verfolgen.

Wenn der Finalizer sich nicht darum kümmert, weiß ich nicht, ob Windows selbst bemerkt, dass der Prozess den Mutex nicht mehr besitzen kann, da er (der Prozess) gar nicht existiert Mehr. Ich vermute es wird, aber Sie müssten detaillierte Win32-Dokumentation überprüfen, um sicher zu sein.

+1

Sie haben recht, es ruft Dispose statt Close auf, obwohl es sich in diesem Fall als identisch herausstellt (Close calls Dispose). Die SDK-Dokumentation besagt, dass der Mutex beim Beenden des Programms freigegeben wird. Wie du, bevorzuge ich aus dem gleichen Grund. –

+0

Ich habe gerade diese Frage gesehen, da der Aufruf von Application.Run (new Form1()) erst zurückkehrt, wenn der Prozess heruntergefahren wird, also ist der Aufruf GC.KeepAlive (m) eigentlich nicht wichtig, habe ich recht? – Benny

+4

@Benny: Ja ist es - denn ohne diesen Aufruf kann das Objekt Müll gesammelt werden. Die Tatsache, dass der Aufruf von "GC.KeepAlive" existiert, bedeutet, dass der GC gezwungen ist, "m" als "Wurzel" -Referenz zu betrachten. –

5

Die Verwendung von using scheint in diesem Fall besser zu passen als die Verwendung von GC.KeepAlive. Sie möchten nicht nur die Mutex am Leben erhalten, solange die Anwendung ausgeführt wird, Sie wollen auch, dass es verschwindet, sobald Sie die Hauptschleife beenden.

Wenn Sie die Mutex einfach hängen lassen, ohne sie zu entsorgen, kann es einige Zeit dauern, bis sie abgeschlossen ist, je nachdem, wie viele Aufräumarbeiten es zu tun gibt, wenn die Anwendung heruntergefahren wird.

-2

Ich denke, der Grund, warum KeepAlive mit dem benannten Mutex verwendet wird, ist sicherzustellen, dass es nicht Garbage früh gesammelt wird. Das C# -Verwendungs-/Dispose-Muster ist nicht dafür geschützt. Wenn eine Objektreferenz nicht mehr in einem Bereich verwendet wird, kann die Laufzeitumgebung sie vor dem Ende des Bereichs erfassen. Es ist eine Optimierung.

+1

<< Die C# Verwendung/Dispose Muster ist nicht dafür geschützt >> Können Sie Beweise zur Untermauerung dieser Behauptung liefern? Entweder ein Testfall oder eine Dokumentation? danke! – EricLaw