C# 如何检测我们是否在 UI 线程上?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1149402/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 09:24:59  来源:igfitidea点击:

How to detect if we're on a UI thread?

c#winformsmultithreadingui-thread

提问by Matthew Scharley

For the sake of argument, consider a UI thread as a thread that has had a call to Application.Run()or one of it's overloads called on it and has an active message loop running.

为了论证起见,将 UI 线程视为已调用Application.Run()或调用其重载之一并运行活动消息循环的线程。

Is there a way of detecting if we're currently executing on such a thread?

有没有办法检测我们当前是否在这样的线程上执行?

The reason I want this is because I have a class with a private function that is long-running. The class itself is already multithreaded, and the usage of this class is such that it might be used from either the UI or from background threads doing processing. This function also falls into this net. But I don't want it to block up the UI thread. So I want to detect if I am running on a UI thread and if so, fork the function call into a background thread (probably ThreadPool, but that's a non-issue for this discussion). This is entirely well-behaved, but the background threads are probably relying on the output of the function, so blocking for them is better, whereas the UI thread is accessing it in a more "set-and-forget" manner.

我想要这个的原因是因为我有一个带有长期运行的私有函数的类。该类本身已经是多线程的,并且该类的使用使得它可以从 UI 或从进行处理的后台线程中使用。这个功能也属于这个网络。但我不希望它阻塞 UI 线程。所以我想检测我是否在 UI 线程上运行,如果是,则将函数调用分叉到后台线程(可能ThreadPool,但这不是本次讨论的问题)。这完全是正常的,但后台线程可能依赖于函数的输出,因此对它们进行阻塞更好,而 UI 线程以更“一劳永逸”的方式访问它。

采纳答案by Jon Skeet

I would suggest that it's the kind of decision the caller should make. You could always write wrapper methods to make it easier - but it means that you won't have problems with the caller being in an "odd" situation (e.g. a UI framework you don't know about, or something else with an event loop) and you making the wrong decision for them.

我建议这是调用者应该做出的决定。您总是可以编写包装器方法以使其更容易 - 但这意味着您不会遇到调用者处于“奇怪”情况(例如,您不知道的 UI 框架,或其他带有事件循环的东西)的问题) 而你为他们做出了错误的决定。

If the method ever needs to provide feedback in the right thread, I'd pass in an ISynchronizeInvoke(implemented by Control) to do that in a UI-agnostic way.

如果该方法需要在正确的线程中提供反馈,我会传入一个ISynchronizeInvoke(由 实现Control)以与 UI 无关的方式执行此操作。

回答by Fredrik M?rk

If you have access to a Formor a Control, you can check the InvokeRequiredproperty; this will return falseif you are on the UI thread and trueif you are not.. If it happens in a context where you cannot check against a Control, you could easily set up a static property in your program that you could check against. Store a reference to Thread.CurrentThreadat startup, and compare Thread.CurrentThreadto that reference when you need to know:

如果您有权访问 aForm或 a Control,则可以检查该InvokeRequired属性;false如果您在 UI 线程上,true如果您不在UI 线程上,这将返回......如果它发生在您无法检查 a 的上下文中Control,您可以轻松地在您的程序中设置一个可以检查的静态属性。Thread.CurrentThread在启动时存储对的引用,并Thread.CurrentThread在您需要知道时与该引用进行比较:

static class Program
{
    private static Thread _startupThread = null;

    [STAThread]
    static void Main()
    {
        _startupThread = Thread.CurrentThread;

        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());
    }

    public static bool IsRunningOnStartupThread()
    {
        return Thread.CurrentThread == _startupThread;
    }
}

By calling Program.IsRunningOnStartupThreadyou will get a boolsaying if you are or not.

通过打电话,Program.IsRunningOnStartupThread你会得到一个bool说法,如果你是或不是。

回答by Ross Anderson

bool isMessageLoopThread = System.Windows.Forms.Application.MessageLoop;

bool isMessageLoopThread = System.Windows.Forms.Application.MessageLoop;