Benannte Threads
Beim Debuggen von Anwendungen mit mehreren Threads fragt man sich mitunter, in welchem Thread man sich gerade durch den Debugger quält. Im VC6 gibt es ein Thread-Fenster, was aber nur den Namen der Startfunktion des Threads bzw. den der aktuellen Funktion anzeigt. Sobald man mehrere Threads mit den gleichen Funktionen zu debuggen hat, wird die Unterscheidung schwer, welcher Thread gerade aktiv ist:
In der MSDN-Library ist beschrieben, wie man durch das Auslösen einer bestimmten Exception die einzelnen Threads benennen kann. Hierzu wird eine Struktur definiert, die u.a. mit dem Namen und der entsprechenden Thread-ID initialisiert wird. Anschließend wird eine Exception ausgelöst. Erfolgt der Aufruf zum Setzen des Namens für den aktuellen Thread, so kann als Thread-ID auch -1 übergeben werden. Zu beachten ist, dass der Name des Threads immer in Ansi (und nicht in Unicode) angegeben wird.
typedef struct tagTHREADNAME_INFO { DWORD dwType; // Typ (muss 0x1000 sein) LPCSTR pszName; // Zeiger auf den Threadnamen (ANSI) DWORD dwThreadID; // Thread-ID (-1 fuer den aufrufenden Thread) DWORD dwFlags; // Reserviert (muss 0 sein) } THREADNAME_INFO; void Lwl_SysSetThreadName(DWORD dwThreadID, LPCSTR pszThreadName) { // Struktur initialisieren THREADNAME_INFO info; info.dwType = 0x1000; info.pszName = pszThreadName; info.dwThreadID = dwThreadID; info.dwFlags = 0; // Exception generieren __try { RaiseException(0x406D1388, 0, sizeof(info)/sizeof(DWORD), (DWORD_PTR*) &info); } // __except(EXCEPTION_CONTINUE_EXECUTION) { } }
Beim Aufruf des Thread-Fensters werden die Threads nun mit ihrem Namen angezeigt. Beim VC6 besteht leider eine Limitierung des Namens auf 9 Zeichen, die im aktuellen Visual Studio 2003 aber aufgehoben ist.
Auch in der .netten Welt mag es manchmal hilfreich sein, wenn man mehrere Threads anhand des Namens unterscheiden kann. In der Regel präsentiert sich das Thread-Fenster wie folgt:
Der Threadname für den Debugger lässt sich direkt über die Eigenschaft Name der Thread-Klasse des .NET-Frameworks festlegen.
Public Class Form1 : Inherits Form Class Needle ' This method will be called when the thread is started Sub Baz() Console.WriteLine("Needle Baz is running on another thread") End Sub End Class Public Shared Sub Main() Console.WriteLine("Thread Simple Sample") Dim oNeedle As New Needle() ' Create a Thread object Dim oThread As New Thread(AddressOf oNeedle.Baz) ' Set the Thread name to "MainThread" oThread.Name = "MainThread" ' Starting the thread invokes the ThreadStart delegate oThread.Start() End Sub End Class
Der Zugriff auf das Thread-Objekt des Prozesses erfolgt über Thread.GetCurrentThread. Nach dem Setzen der Threadnamen sieht das Fenster im Debugger nun so aus:
Wenn Du einen Handler für C-Exception nach C++-Exceptions installiert hast (via _set_se_translator), solltest Du den glaube ich in Lwl_SysSetThreadName aber temporär entfernen…
Mit _set_se_translator habe ich leider noch keinerlei Erfahrung gemacht…