在exploding with excitement了解如何对Windows窗体控件进行线程安全调用之后,它让我想到了......
为什么所有调用Windows窗体控件都不是线程安全的?任何人都可以解释原因吗?我认为这会减少对这些控件的用户的很多困惑。
答案 0 :(得分:8)
这里的问题不是线程安全问题。这些方法都是“线程安全的”,因为它们在多个线程上同时调用时不会破坏应用程序的状态 - 只是线程安全包括抛出错误的线程异常(无法记住它的名称)。 / p>
他们拥有的是线程无限 - 他们只能在一个线程上调用 - 有时也称为UI线程,尽管这是误导性的,因为它意味着只有一个。这主要是因为它们依赖的OS调用具有相同的线程关联规则。
相信我 - 这是好的事情。当您考虑“UI线程”的主要角色时,一切都开始变得清晰。 UI线程作业是通过键盘或鼠标从用户手中获取输入,对其进行操作,并以响应的像素形式产生输出。只有一个用户,该用户只有一组眼睛。用户希望在屏幕上看到他们所做的一切,最重要的是他们希望看到它按照他们的顺序发生。多线程UI会使这很难实现 - 几乎不可能。
问题在于,当您将后台“工作”线程与UI线程混合时,您需要执行一定数量的编组以与UI进行通信,因为您必须在UI线程上执行此操作。再说一遍,正如我所说,这是一件好事。有人必须进行这种编组操作,否则用户会看到事情发生的顺序错误而且很糟糕。系统可以肯定地为你做,并在一些WIN32调用它 - 但这有问题。首先,系统无法知道您需要进行编组所需的粒度,因此最终可能会导致效率低下。您的操作可能会在系统可以理解的更高级别上进行编组。其次,编组是昂贵的,它会惩罚正在做正确事情并将所有内容正确地移动到UI线程的开发人员。所以系统尽其所能,检查它是否在正确的线程上,如果不是,则抛出异常。
答案 1 :(得分:5)
因为它会降低性能并编写lock-free线程安全代码仍然是一个活跃的研究领域。
答案 2 :(得分:3)
实际问题是Windows窗体使用本机资源(例如GDI对象)来呈现窗体/控件。
这些GDI资源只能在创建它们的线程中使用,很可能是主线程。
因此,任何需要更新gui并因此使用GDI资源重绘的表单/控件的调用必须在主线程上进行。
因此,来自其他想要执行此操作的线程的调用必须编组到主线程中。 我不太确定这是如何在幕后工作的,但我想通过将消息发布到表单/组件的wnd proc来实现这一点。 一旦主线程在wndproc中处理此消息,它就可以调用实际代码。 这将是非常昂贵的表现。
答案 3 :(得分:2)
扩展达林的回答:
大多数情况下,Windows窗体控件不需要是线程安全的,因为它们通常是从UI线程访问的。
偶尔他们会这样做(例如你的代码中)。
因此,添加线程检查代码会给95%以上不需要的情况增加不可接受的性能开销。