在 UI 线程上调用 Task.Factory.StartNew 会怎样?

4
我需要处理一个奇怪的问题,至少在我看来是这样。我使用一个任务来等待变量获得特定的值,然后再次在UI线程上运行Continue部分。
现在的问题是,在调用StartNew()之前和其中,ManagedThreadId相同,并且它会冻结我的UI。
以下是我的代码:
// ManagedThreadId here
Task.Factory.StartNew(() => 
{
    // and here are the same.
    while (isClosing)
    {
        Thread.Sleep(50);
    }
}).ContinueWith((finishedTask) => 
{
    if (currentContainer != null)
    {
        window = currentContainer;
    }
    else
    {
         window = CreateBallonWindow();
         window.Show();
    }

    window.Activate();
}, TaskScheduler.FromCurrentSynchronizationContext());

有什么想法吗?

谢谢克里斯托夫。

编辑:

对我来说最有趣的是为什么会出现这种情况,而不是如何解决这个问题。我想了解那里发生了什么...


是的,但我不想每次关闭窗口时都引发一个操作。我只想确保在打开新窗口时它已经关闭了。此外,对我来说更有趣的是如何解决这个问题,因为我想了解为什么两者在同一线程上执行。如果我的问题没有表达清楚,那我很抱歉。 - christoph
我已经快速制作了一个样例应用程序,对我来说它运行良好。但是,当你查询管理的ID时,你是否将其放入一个被闭包包装的变量中?我的UI线程ID为9,我的内部线程ID(来自ThreadPool)为10。 - Adam Houldsworth
3
Task.Factory.StartNew 不能保证生成一个新的线程。请参考 此答案 了解更多详细信息,同时也请查看其前两个评论。正如链接答案中的第四条评论所述,您还可以尝试指定 TaskCreationOptions.LongRunning ,以强制为任务生成一个新线程。 - Viv
@Viv 如果没有提供默认的TaskScheduler,它不使用吗?对我来说,这是线程池(根据我的调试器)。 - Adam Houldsworth
在运行时检查 TaskScheduler.FromCurrentSynchronizationContext() 返回的内容。如果您已经在线程池上,则线程ID可能保持不变。 - usr
显示剩余9条评论
1个回答

3
谢谢大家的提示,
我终于想出了答案。问题在于TaskScheduler.Current是调用StartNew()时使用的默认调度程序。当使用TaskScheduler.SynchronizationContext()时,这种组合不好。
情况是我(间接地)在继续任务中使用了StartNew()和由TaskScheduler.SynchronizationContext()描述的调度程序。因此,默认的调度程序是包含UI线程的那个-->新任务在UI线程上被调用。
特别感谢Viv分享的链接,帮助我理解了其中的问题。
Christoph

那正是我怀疑的 :) 不知何故使用了错误的调度程序或同步上下文来调用StartNew。 - usr
@usr 是的,但如果你在我发布问题后立即回答,我想我不会明白,没有所有评论的帮助 :) - christoph

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