【发布时间】:2014-11-04 22:45:23
【问题描述】:
我对接下来的情况有点困惑。如果我调用SleepBeforeInvoke 方法,应用程序将在_task.Wait(); 字符串上挂起。但如果我调用SleepAfterInvoke 方法,应用程序工作正常,控制将达到catch 子句。调用BeginInvoke 方法也可以正常工作。
谁能详细解释这三种方法的用法有什么区别?如果我使用SleepBeforeInvoke 方法,为什么应用程序会暂停,如果我使用SleepAfterInvoke 和BeginInvoke 方法,为什么不会?谢谢。
Win 7、.Net 4.0
xaml:
<Grid>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0"
Name="_textBlock"
Text="MainWindow"></TextBlock>
<Button Grid.Row="1"
Click="ButtonBase_OnClick"></Button>
</Grid>
.cs:
public partial class MainWindow : Window
{
private readonly CancellationTokenSource _cts = new CancellationTokenSource();
private Task _task;
/// <summary>
/// Application wiil be suspended on string _task.Wait();
/// </summary>
private void SleepBeforeInvoke()
{
for (Int32 count = 0; count < 50; count++)
{
if (_cts.Token.IsCancellationRequested)
_cts.Token.ThrowIfCancellationRequested();
Thread.Sleep(500);
Application.Current.Dispatcher.Invoke(new Action(() => { }));
}
}
/// <summary>
/// Works fine, control will reach the catch
/// </summary>
private void SleepAfterInvoke()
{
for (Int32 count = 0; count < 50; count++)
{
if (_cts.Token.IsCancellationRequested)
_cts.Token.ThrowIfCancellationRequested();
Application.Current.Dispatcher.Invoke(new Action(() => { }));
Thread.Sleep(500);
}
}
/// <summary>
/// Works fine, control will reach the catch
/// </summary>
private void BeginInvoke()
{
for (Int32 count = 0; count < 50; count++)
{
if (_cts.Token.IsCancellationRequested)
_cts.Token.ThrowIfCancellationRequested();
Thread.Sleep(500);
Application.Current.Dispatcher.BeginInvoke(new Action(() => { }));
}
}
public MainWindow()
{
InitializeComponent();
_task = Task.Factory.StartNew(SleepBeforeInvoke, _cts.Token, TaskCreationOptions.None, TaskScheduler.Default);
}
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
try
{
_cts.Cancel();
_task.Wait();
}
catch (AggregateException)
{
}
Debug.WriteLine("Task has been cancelled");
}
}
【问题讨论】:
-
任务异步应该取代你对线程的需求。除非您知道自己在做什么,否则请坚持使用单线程异步。另请阅读 Stephen Cleary 关于异步的博客。
-
@Aron, .net 4.0 :( 没有异步等待
-
我建议在这种情况下使用 Rx.Net。或者升级......说真的......值得升级......如果只是因为
Task在.net 4.0中被破坏,不要使用它。Task.ContinueWith#$%*s up yourSynchronizationContext.Current,基本上破坏了 WinForms 和 WPF。 -
@Aron, broken 是一个非常强烈的词。您应该为那些对该主题感兴趣的人(例如我自己)提供一些高质量的阅读来支持您的评论。
标签: c# wpf task suspend cancellation