Как определить, является ли поток основным потоком в С#
Я знаю, что есть другие сообщения, которые говорят, что вы можете создать элемент управления, а затем проверить свойство InvokeRequired
, чтобы увидеть, является ли текущий поток основным потоком или нет.
Проблема в том, что у вас нет способа узнать, был ли этот элемент управления создан в основном потоке.
Я использую следующий код, чтобы определить, является ли поток основным потоком (поток, который запустил процесс):
if (Thread.CurrentThread.GetApartmentState() != ApartmentState.STA ||
Thread.CurrentThread.ManagedThreadId != 1 ||
Thread.CurrentThread.IsBackground || Thread.CurrentThread.IsThreadPoolThread)
{
// not the main thread
}
Кто-нибудь знает лучший способ? Похоже, что этот способ может быть подвержен ошибкам или ломаться в будущих версиях среды выполнения.
Ответы
Ответ 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