Подтвердить что ты не робот

Как определить, является ли поток основным потоком в С#

Я знаю, что есть другие сообщения, которые говорят, что вы можете создать элемент управления, а затем проверить свойство InvokeRequired, чтобы увидеть, является ли текущий поток основным потоком или нет.

Проблема в том, что у вас нет способа узнать, был ли этот элемент управления создан в основном потоке.

Я использую следующий код, чтобы определить, является ли поток основным потоком (поток, который запустил процесс):

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

Кто-нибудь знает лучший способ? Похоже, что этот способ может быть подвержен ошибкам или ломаться в будущих версиях среды выполнения.

4b9b3361

Ответ 1

Вы можете сделать это следующим образом:

// 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 Я понял, что вы тоже можете сделать это с отражением, вот фрагмент для этого:

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

Ответ 2

Если вы используете Windows Forms или WPF, вы можете проверить, нет ли SynchronizationContext.Current.

Основной поток получит действительный SynchronizationContext, установленный в текущем контексте при запуске в Windows Forms и WPF.

Ответ 3

Вот еще один вариант:

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

Работает для меня.

EDIT: Забыл упомянуть, что это работает только в WPF. Я искал SO для случая WPF, и я не заметил, что этот вопрос является общим .NET. Другим вариантом для Windows Forms может быть

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

Конечно, сначала вы должны убедиться, что в приложении есть хотя бы один Form.

Ответ 4

Попробуйте этот if (Application.MessageLoop). Я думаю, что редко бывает иметь более 1 потока для обработки сообщений

Ответ 5

По моему опыту, если вы попытаетесь создать диалог из другого потока, отличного от основного потока, тогда окна все запутаются, и все начнет сходить с ума. Я попытался сделать это один раз с окном состояния, чтобы показать статус фонового потока (как и многие другие случаи, когда кто-то подбрасывал диалог из фонового потока - и тот, у которого был Message Loop) - и Windows только началась делая "случайные" вещи в программе. Я почти уверен, что было какое-то небезопасное обращение с чем-то происходящим. Были проблемы с нажатием на форму и неправильный поток, обрабатывающий сообщения...

Итак, у меня никогда не было бы никакого пользовательского интерфейса, следующего из Anywhere, но основного потока.

Однако почему бы просто не отключить CurrentThread при запуске и сравнить ThreadID с текущим потоком?

-Chert