Hoe weet je of een thread de hoofdthread is in C#

Er zijn andere berichten die zeggen dat je een besturingselement in Windows-formulieren kunt maken en vervolgens de eigenschap InvokeRequiredkunt controleren om te zien of de huidige thread de hoofdthread is of niet.

Het probleem is dat je niet kunt weten of dat besturingselement zelf in de hoofdthread is gemaakt.

Ik gebruik de volgende code om te zien of een thread de hoofdthread is (de thread waarmee het proces is gestart):

if (Thread.CurrentThread.GetApartmentState() != ApartmentState.STA ||
    Thread.CurrentThread.ManagedThreadId != 1 ||
    Thread.CurrentThread.IsBackground || Thread.CurrentThread.IsThreadPoolThread)
{
    // not the main thread
}

Weet iemand een betere manier? Het lijkt erop dat deze manier vatbaar is voor fouten of onderbrekingen in toekomstige versies van de runtime.


Antwoord 1, autoriteit 100%

Je zou het als volgt kunnen doen:

// Do this when you start your application
static int mainThreadId;
// In Main method:
mainThreadId = System.Threading.Thread.CurrentThread.ManagedThreadId;
// If called in the non main thread, will return false;
public static bool IsMainThread
{
    get { return System.Threading.Thread.CurrentThread.ManagedThreadId == mainThreadId; }
}

EDITIk realiseerde me dat je het ook met reflectie zou kunnen doen, hier is een fragment daarvoor:

public static void CheckForMainThread()
{
    if (Thread.CurrentThread.GetApartmentState() == ApartmentState.STA &&
        !Thread.CurrentThread.IsBackground && !Thread.CurrentThread.IsThreadPoolThread && Thread.CurrentThread.IsAlive)
    {
        MethodInfo correctEntryMethod = Assembly.GetEntryAssembly().EntryPoint;
        StackTrace trace = new StackTrace();
        StackFrame[] frames = trace.GetFrames();
        for (int i = frames.Length - 1; i >= 0; i--)
        {
            MethodBase method = frames[i].GetMethod();
            if (correctEntryMethod == method)
            {
                return;
            }
        }
    }
    // throw exception, the current thread is not the main thread...
}

Antwoord 2, autoriteit 36%

Als u Windows Forms of WPF gebruikt, kunt u controleren of SynchronizationContext.Currentis niet null.

De hoofdthread krijgt een geldige SynchronizationContextingesteld op de huidige context bij het opstarten in Windows Forms en WPF.


Antwoord 3, autoriteit 25%

Het is veel eenvoudiger:

static class Program
{
  [ThreadStatic]
  public static readonly bool IsMainThread = true;
//...
}

En je kunt het vanuit elke thread gebruiken:

if(Program.IsMainThread) ...

Uitleg:

De initializer van het IsMainThread-veld wordt gecompileerd tot een statische constructor die wordt uitgevoerd wanneer de klasse voor het eerst wordt gebruikt (technisch gezien vóór de eerste toegang van een statisch lid). Ervan uitgaande dat de klasse eerst in de hoofdthread wordt gebruikt, wordt de statische constructor aangeroepen en wordt het veld op de hoofdthread ingesteld op true.

Omdat het veld het kenmerk [ThreadStatic]heeft, heeft het een onafhankelijke waarde in elke thread. De initialisatie wordt slechts één keer uitgevoerd, in de eerste thread die toegang heeft tot het type, dus de waarde in die thread is true, maar het veld blijft niet geïnitialiseerd in alle andere threads, met een waarde van false.


Antwoord 4, autoriteit 25%

In een WPF-app is hier nog een andere optie:

if (App.Current.Dispatcher.Thread == System.Threading.Thread.CurrentThread)
{
    //we're on the main thread
}

In een Windows Forms-app werkt dit zolang er tenminste één Formopen is:

if (Application.OpenForms[0].InvokeRequired)
{
    //we're on the main thread
}

Antwoord 5, autoriteit 2%

Mijn ervaring is dat als je probeert een dialoog te maken vanuit een andere thread dan de hoofdthread, Windows in de war raakt en dingen gek worden. Ik heb geprobeerd dit een keer te doen met een statusvenster om de status van de achtergrondthread weer te geven (evenals vele andere keren dat iemand een dialoogvenster uit een achtergrondthread zou gooien – en een die wel een Message Loop had) – en Windows is net begonnen “willekeurige” dingen doen in het programma. Ik ben er vrij zeker van dat er iets onveiligs gebeurde. Had problemen met het klikken op het formulier en de verkeerde thread om de berichten te verwerken…

Dus ik zou nooit een gebruikersinterface hebben die overal vandaan komt, behalve de hoofdthread.

Waarom slaat u echter niet gewoon de CurrentThread op als u begint en vergelijkt u de ThreadID met de huidige thread?

-Cert

Other episodes