开发者

How to tell if a thread is the main thread in C#

开发者 https://www.devze.com 2022-12-21 17:09 出处:网络
There are other posts that say you can create a control in windows forms and then check the InvokeRequired property to see if the current thread is the main thread or not.

There are other posts that say you can create a control in windows forms and then check the InvokeRequired property to see if the current thread is the main thread or not.

The problem is that you have no way of knowing if that control itself was created on the main thread.

I am using the following code to tell if a thread is the main thread (the thread that started the process):

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

Does anyone know a better way? It seems like this way might be prone to errors or break开发者_StackOverflow中文版 in future versions of the runtime.


You could do it like this:

// 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; }
}

EDIT I realized you could do it with reflection too, here is a snippet for that:

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...
}


If you're using Windows Forms or WPF, you can check to see if SynchronizationContext.Current is not null.

The main thread will get a valid SynchronizationContext set to the current context upon startup in Windows Forms and WPF.


In a WPF app, here is another option:

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

In a Windows Forms app, this will work as long as there's at least one Form open:

if (!Application.OpenForms[0].InvokeRequired)
{
    //we're on the main thread, since invoking is NOT required
}


It is much more easy:

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

//...
}

And you can use it from any thread:

if(Program.IsMainThread) ...

Explanation:

The IsMainThread field's initializer gets compiled into a static constructor which gets run when the class is first used (technically, before the first access of any static member). Assuming the class is first used on the main thread, the static constructor will be called and the field will be set to true on the main thread.

Since the field has the [ThreadStatic] attribute, it has an independent value in each thread. The initializer runs only once, in the first thread that accesses the type, so the value in that thread is true, but the field remains uninitialized in all other threads, with a value of false.


In my experience, if you attempt to create a dialog from another thread other than the main thread then windows gets all confused and things start going crazy. I tried to do this once with a status window to show the status of the background thread (as well as many other times someone would toss up a dialog from a background thread - and one that did have a Message Loop) - and Windows just started doing "random" things in the program. I'm pretty sure there was some unsafe handling of something going on. Had issues with clicking on the form and the wrong thread handling the messages...

So, I would never have any UI coming up from Anywhere but the main thread.

However, Why not simply save off the CurrentThread when you start, and compare the ThreadID with the current thread?

-Chert

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号