WinRT是否仍然具有相同的UI线程限制?

16

在WinForms中,你的UI基本上都是线程特定的。你必须使用[STAThread]使常见对话框工作,并且不能(安全地)从创建它的任何线程以外的线程访问UI元素。据我所知,那是因为这就是Windows的工作原理--窗口句柄是线程特定的。

在WPF中,这些相同的限制被保留了,因为它最终仍然是建立在同样的Windows API之上,仍然是窗口句柄(虽然大多数只是针对顶层窗口),等等。事实上,WPF甚至使事情更加限制,因为你甚至不能跨线程访问像位图之类的东西。

现在出现了WinRT,一种全新的访问Windows的方式--一个全新的、干净的界面。我们是否仍然被困在相同的旧线程限制中(具体来说:只能从创建它的线程操作UI控件),还是已经打开了这个限制?


我希望我们有相同的线程模型。如果允许自由混乱或在各处强制执行内部锁定,那将是疯狂的。 - David Heffernan
5个回答

9

我希望它是相同的模型,但更易于使用,至少对于C#和VB来说是这样,新的异步处理使您能够编写一个看起来像同步方法的方法,只需在需要等待长时间运行的任务完成后再继续之前使用“await”。

鉴于强调使异步代码更容易编写,令人惊讶的是MS同时放弃要求单线程访问UI的效率。


据我理解,“await”并未指定在哪个线程上运行续体,它可能会在工作线程上运行。因此这并没有使得与UI相关的异步代码更容易;你仍需要手动编写大量代码以将调用封送到UI线程。 - Joe White
3
@Joe:虽然 await 本身不需要任何东西(规范只是说明生成的代码将调用什么),但它取决于可等待对象的操作。默认情况下,Task<T> 将捕获当前上下文并在同一上下文中安排继续执行 - 因此,如果在 UI 线程中执行 await,则继续执行也将在 UI 线程上执行。这是异步/等待的一个重要优点之一 - 即您不需要编写大量代码来执行封送处理。 - Jon Skeet

5
线程模型是相同的。仍然存在单线程和多线程公寓(STA / MTA),必须通过调用RoInitialize来初始化。这很像CoInitialize的名称,参数和错误返回。用户界面线程是单线程的,在此视频中确认了这一点。

我不记得那次讲话中有任何涉及UI线程的内容,而且在36:00处也没有相关内容。在36:54处,他说“你的大部分应用程序代码将在单线程公寓中运行”——这是你所指的吗?但这听起来只是在谈论常见做法;毕竟,STA更容易编写。这似乎并不能明确地说明WinRT中的UI 需要单线程公寓。 - Joe White
他演示了主线程被初始化为STA。另外,需要注意的是在WinRT中不允许创建自己的线程,只能调用异步操作,并且可选项非常有限。 - Hans Passant
嗯...我记得看到只能使用Task进行线程处理,而这并不适用于显示UI,所以我想你关于被困在初始线程模型中是正确的。虽然他正在开发一个HTML5应用程序,但是该线程初始化都是在HTML5应用程序的主机EXE中进行的。您是否遇到过任何说明XAML应用程序也受限于STA的内容? - Joe White

2

底层的线程模型确实存在一些关键差异。当你的应用程序启动时,将创建一个ASTA(应用STA)来运行你的UI代码,正如我在演讲中所展示的那样。这个ASTA不允许重入 - 在进行外部调用时,您将不会收到无关的调用。这是与STAs相比的一个显著区别。

你可以创建异步工作项 - 参见Windows.System.Threadpool命名空间。这些工作项线程自动初始化为MTA。正如Larry所提到的,WebWorkers是JS的等效概念。

你的UI组件是线程关联的。请参见Windows.UI.Core.CoreDispatcher类以获取有关在UI线程上执行代码的信息。您可以查看线程示例以获取一些示例代码,以从异步操作更新UI。


1
这是一个关于线程示例的链接:http://code.msdn.microsoft.com/windowsapps/Pool-Sample-5aa60454#content。显然我没有足够的声望来发布超过两个链接 :) - Matthew Merry

2

HTML/CSS用户界面模型本质上是单线程的(直到最近Web Workers的出现,JS才支持线程)。Xaml也是单线程的(因为对于开发人员来说,编写多线程GUI代码实在是太难了)。


1

在相当重要的方面,事情是不同的。

虽然底层线程模型是相同的,但你的问题通常涉及逻辑并发如何与UI一起工作,就此而言,在Windows 8中开发人员看到的将是新的。

正如你提到的,大多数对话框以前都被阻止了。对于Metro应用程序,许多UI组件不会全部阻止。还记得WinRT异步吗?它也适用于UI组件。

例如,这个.NET 4代码不一定会因为UI调用在Show上阻塞而杀死你的硬盘(C#示例):

bool formatHardDrive = true;
if (MessageBox.Show("Format your harddrive?") == NO)
    formatHardDrive = false;
if (formatHardDrive == true)
    Format(); 

随着Windows 8 Metro的推出,许多UI组件如Windows.UI.Popups.MessageDialog默认情况下是异步的,因此Show调用会立即(逻辑上)执行到代码的下一行,而不会等待用户输入。

当然,基于await/promise设计模式有一个优雅的解决方案(JavaScript示例):

var md = Windows.UI.Popups.MessageDialog("Hello World!");
md.showAsync().then(function (command) { 
    console.log("pressed: " + command.label); });

重点在于,虽然线程模型不会改变,但当大多数人提到UI和线程时,他们考虑的是逻辑并发性以及它如何影响编程模型。

总体而言,我认为异步范式转变是一件好事。它需要一些视角上的转变,但与客户端和服务器端上其他平台的演进方式保持一致。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接