AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Win32/Win64 API (native code) C# Timing und Multithreading unter .NET
Thema durchsuchen
Ansicht
Themen-Optionen

Timing und Multithreading unter .NET

Ein Thema von OregonGhost · begonnen am 26. Nov 2006
Antwort Antwort
OregonGhost

Registriert seit: 8. Jun 2002
Ort: Lübeck
1.216 Beiträge
 
Delphi 3 Professional
 
#1

Timing und Multithreading unter .NET

  Alt 26. Nov 2006, 14:41
Also, mal vorne anfangen. Ich hab eine Anwendung, die Managed DirectX verwendet. Es kommt zwar nicht unbedingt auf eine exakte Animation an, aber während der Entwicklung weiß ich gerne, wie lange das Rendern eines Frames dauert. Diese Information bekomme ich exakt genug nur von QueryPerformanceCounter (eventuelle Ungenauigkeiten und Korrektursprünge interessieren mich hierbei nicht). Ich habe mir also eine Timer-Klasse geschrieben, die die beiden nötigen Funktionen importiert und eine Start- und Stop-Methode hat, mit denen ich die Zeit messen kann. Das Problem hierbei ist, dass bekanntermaßen auf vielen Dual-Core-Systemen, darunter auch auf meinem, jeder Prozessor bzw. Kern unterschiedliche Werte liefert, so dass auch negative Werte möglich sind. Das ist natürlich nicht sehr günstig. Die empfohlene Problemlösung hierzu ist, den Timing-Code immer auf demselben Prozessor auszuführen. In der nativen Welt ist das natürlich nicht das geringste Problem, ein SetThreadAffinityMask mit dem aktuellen Thread und das Problem ist gegessen. In .NET scheint die Geschichte nicht so einfach zu sein. Ich habe jetzt eine Lösung, aber sie ist etwas unelegant (finde ich), daher möchte ich gerne weitere Meinungen dazu einholen oder auch Vorschläge. Auch eine Alternative zu QPF wäre nett, aber es scheint keine gute Möglichkeit zu geben.

Also, zunächst kann man über Process.ProcessorAffinity den gesamten Prozess an einen Prozessorkern binden. Der Timing-Code funktioniert dann, nur leider brauche ich einen zweiten Thread. Über ProcessThread.ProcessorAffinity kann man einen einzelnen nativen Thread an einen Prozessor binden, aber ein Managed Thread hat nicht unbedingt etwas mit einem nativen Thread zu tun. Also muss ich die beiden auch noch zusammen bringen. Das sieht ungefähr so aus:
Code:
public static void BindThread(IntPtr mask)
{
    if (ProcessThread != null) {
        UnbindThread();
    }

    System.Threading.Thread.BeginThreadAffinity();
    uint id = GetCurrentThreadId();
    foreach (ProcessThread thread in Process.GetCurrentProcess().Threads) {
        if (thread.Id == id) {
             ProcessThread = thread;
        }
    }
    ProcessThread.ProcessorAffinity = mask;  
}

public static void UnbindThread()
{
    if (ProcessThread != null) {
        System.Threading.Thread.EndThreadAffinity();
        ProcessThread.ProcessorAffinity = Process.GetCurrentProcess().ProcessorAffinity;
        ProcessThread = null;
    }
}
Ich binde also meinen verwalteten Thread an einen nativen Thread, und den binde ich an einen Prozessorkern, der Einfachheit halber an den ersten. Das scheint soweit auch zu funktionieren. Natürlich ist das eine recht zeitaufwändige Sache, so dass man das am Anfang der Anwendung machen muss (nicht etwa in jedem Frame). Dadurch gilt die Threadbindung natürlich für die gesamte Laufzeit der Anwendung. Ich weiß, ich könnte, wenn ich die Thread-ID schon über die Windows-API holen muss, auch die Affinität darüber setzen, aber ich hab so mein ProcessThread-Objekt, finde ich angenehmer, zumal ich so nur insgesamt drei Funktionen importieren muss.
So, und nun zu meiner Frage.
Gibt es eine bessere Methode für hochauflösendes Timing unter .NET? Wenn nein, ist meine Implementierung vernünftig?

Edit:
Mir ist gerade aufgefallen, dass ich als erstes meinen managed Thread an den nativen binden sollte, bevor ich den Rest mache. Sonst könnte mein verwalteter Thread ja nach dem GetCurrentThreadId, aber vor (oder auch nach) dem Setzen der Affinität auf einen anderen nativen verschoben werden. Ich habe den Code diesbezüglich korrigiert.
Oregon Ghost
---
Wenn NULL besonders groß ist, ist es fast schon wie ein bisschen eins.
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 08:28 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz