Freitag, 2. Juli 2010

CPU Auslastung auslesen

Um mit C# die Auslastung des Prozessors auszulesen, bedienen wir uns der Klasse PerformanceCounter.
Mit dieser können allgemein Leistungsdaten gemessen werden und, wenn wir dieser Klasse die richtigen Eigenschaften übergeben, eben auch die der CPU.
Bei einer Instanz der Klasse PerformanceCounter müssen folgende Eigenschaften gesetzt werden, damit die Auslastung des Prozessors ausgelesen werden kann:
  • CategoryName = "Processor". Hiermit geben wir dem Programm die grobe Kategorie der zu überwachenden Leistungsdaten mit.
  • CounterName = "% Processor Time". Mit dieser Eigenschaft wird der genaue Name des Leistungsindikators festgelegt.
  • InstanceName = "_Total". Kategorien können in verschiedene Instanzen aufgeteilt werden, mit dieser weisen wir das Programm an, die Instanz "_Total" zu nehmen, mit welcher immer die am meisten gefragten Daten aus dieser Kategorie gemeint sind.

Zum Abrufen der Leistungsdaten brauchen wir schließlich die Funktion NextValue().
Bei manchen Leistungsindikatoren aber, und beim Abrufen der Prozessorauslastung ist das der Fall, braucht NextValue() einen Referenzpunkt zum Vergleichen der aktuellen Daten mit dem vorigen Wert.
Da die beiden Aufrufe der Funktionen zeitlich etwas versetzt erfolgen müssen, habe ich im folgenden Beispielprogramm die Abfrage der CPU - Auslastung in einen eigenen Thread verpackt, damit der Fluss des Hauptprogramms nicht unterbrochen wird:

// hiervor die üblichen using Anweisungen
using System.Diagnostics;
using System.Threading;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

        }

        PerformanceCounter CPUCounter = new PerformanceCounter(); // Instanz der Klasse PerformanceCounter
        Thread CPUWatcher; // Thread zum Abfragen der CPU - Auslastung

        private void Form1_Load(object sender, EventArgs e)
        {
            // CPUCounter mit beschriebenen Werten initialisieren
            CPUCounter.CategoryName = "Processor";
            CPUCounter.CounterName = "% Processor Time";
            CPUCounter.InstanceName = "_Total";
          
        }

        // beim Klick auf einen Button wird im Beispielprogramm die CPU - Auslastung abgefragt
        private void button1_Click(object sender, EventArgs e)
        {
            // hierfür wird der Thread CPUWatchner (neu) initialisiert und gestartet
            CPUWatcher = new Thread(new ThreadStart(GetCPUUsage));
            CPUWatcher.Start();
        }

        // im Thread CPUWatcher wird diese Funtkion gestartet
        private void GetCPUUsage()
        {
            // die Funktion ruft NextValue() 2 mal mit einem Abstand von jeweils 1 Sekunde auf,
            // das Ergebnis wird per MessageBox angezeigt
            CPUCounter.NextValue();
            System.Threading.Thread.Sleep(1000);
            MessageBox.Show(CPUCounter.NextValue().ToString());
        }
    }
}

Kommentare:

  1. System.InvalidOperationException -.-

    AntwortenLöschen
  2. Bei welcher Stelle genau?
    Ist das Problem mittlerweile gefunden?

    AntwortenLöschen
  3. Bei mir ebenfalls:
    System.InvalidOperationException

    Wenn ich versuche die CPUUsage in ein Label zu schreiben:

    Ungültiger threadübergreifender Vorgang: Der Zugriff auf das Steuerelement label_CPU_Usage erfolgte von einem anderen Thread als dem Thread, für den es erstellt wurde.

    AntwortenLöschen
  4. Ah okay, dann liegt das Problem gar nicht bei der Operation zur Ermittlung der CPU Auslastung sondern beim Schreiben in das Label.
    Das kommt wahrscheinlich daher, dass der Zugriff auf das Steuerelement von einem anderen Thread erfolgt als von dem Thread, der das Steuerelement erstellt hat (der Hauptthread).
    Dieses wird aus Sicherheitsgründen nicht zugelassen.
    Um den Zugriff trotzdem durchführen zu können, muss dieser "invoked" werden, es muss auf Threadsicherheit geachtet werden.
    Vielleicht poste ich dazu bald mal etwas, für's erste hoffe ich der folgende Verweis auf MSDN reicht: http://msdn.microsoft.com/en-us/library/ms171728(v=vs.80).aspx

    Die wichtigen Stellen für euch sind von folgender Form:

    if (this.textBox1.InvokeRequired)
    {
    SetTextCallback d = new SetTextCallback(SetText);
    this.Invoke(d, new object[] { text });
    }
    else
    {
    this.textBox1.Text = text;
    }

    AntwortenLöschen
  5. Oder etwas eleganter mit anonymen Methoden:

    if (textBox1.InvokeRequired)
    {
    textBox1.Invoke(new Action(() => { textBox1.Text = text; }))
    }
    else
    {
    textBox1.Text = text;
    }

    AntwortenLöschen
  6. Hallo,

    ihr solltet evtl. einen BackgroundWorker verwenden, um die CPU Auslastung abzufragen. Diese schreibt ihr in das Result des BackgroundWorker. Es gibt dann ein Ereignis das ausgelöst wird, nach dem der BackgroundWorker beendet wurde. Diesem Event wird das Result übergeben und man kann es im Thread der GUI auslösen um den Wert in das Label zu schreiben.

    AntwortenLöschen
  7. Echt geniale Beiträge hier Daumen
    hoch hierfür

    AntwortenLöschen