【发布时间】:2011-10-20 01:44:35
【问题描述】:
我是 TPL 和 WPf 的新手,遇到以下问题。 我尝试在无限循环中下载一个站点(这里只有一个 for 循环)和 将其添加到队列中。下一个任务将其取出并显示在文本块中。 但是,尽管我认为我正确使用了 TaskScheduler,但我似乎没有为 UI 找到正确的线程。
感谢您的帮助!
BlockingCollection<string> blockingCollection = new BlockingCollection<string>();
CancellationToken token = tokenSource.Token;
TaskScheduler uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
Task task1 = new Task(
(obj) =>
{
for (int i = 0; i < 10; i++)
{
if (token.IsCancellationRequested)
{
TxtBlock2.Text = "Task cancel detected";
throw new OperationCanceledException(token);
}
else
{
string code = i.ToString() + "\t" + AsyncHttpReq.get_source_WebRequest(uri);
blockingCollection.Add(code);
}
}
}, TaskScheduler.Default);
task1.ContinueWith(antecedents =>
{
TxtBlock2.Text = "Signalling production end";
blockingCollection.CompleteAdding();
}, uiScheduler);
Task taskCP = new Task(
(obj) =>
{
while (!blockingCollection.IsCompleted)
{
string dlCode;
if (blockingCollection.TryTake(out dlCode))
{
//the calling thread cannot access this object because a different thread owns it.
TxtBlock3.Text = dlCode;
}
}
}, uiScheduler);
WindowsBase.dll!System.Windows.Threading.Dispatcher.VerifyAccess() + 0x4a bytes
WindowsBase.dll!System.Windows.DependencyObject.SetValue(System.Windows.DependencyProperty dp, object value) + 0x19 bytes
PresentationFramework.dll!System.Windows.Controls.TextBlock.Text.set(string value) + 0x24 bytes
WpfRibbonApplication4.exe!WpfRibbonApplication4.MainWindow.Button1_Click.AnonymousMethod__4(object obj) 第 83 行 + 0x16 字节 C# mscorlib.dll!System.Threading.Tasks.Task.InnerInvoke() + 0x44 字节 mscorlib.dll!System.Threading.Tasks.Task.Execute() + 0x43 字节 mscorlib.dll!System.Threading.Tasks.Task.ExecutionContextCallback(object obj) + 0x27 bytes
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback 回调, 对象状态, bool ignoreSyncCtx) + 0xb0 bytes
mscorlib.dll!System.Threading.Tasks.Task.ExecuteWithThreadLocal(ref System.Threading.Tasks.Task currentTaskSlot) + 0x154 字节
mscorlib.dll!System.Threading.Tasks.Task.ExecuteEntry(bool bPreventDoubleExecution) + 0x8b 字节
mscorlib.dll!System.Threading.Tasks.Task.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem() + 0x7 字节 mscorlib.dll!System.Threading.ThreadPoolWorkQueue.Dispatch() + 0x147 字节
mscorlib.dll!System.Threading._ThreadPoolWaitCallback.PerformWaitCallback() + 0x2d 字节
[本机到托管转换]
System.InvalidOperationException was unhandled by user code
Message=The calling thread cannot access this object because a different thread owns it.
Source=WindowsBase
StackTrace:
at System.Windows.Threading.Dispatcher.VerifyAccess()
at System.Windows.DependencyObject.SetValue(DependencyProperty dp, Object value)
at System.Windows.Controls.TextBlock.set_Text(String value)
at WpfRibbonApplication4.MainWindow.<>c__DisplayClass5.<Button1_Click>b__3(Object o) in C:\ ... \WpfRibbonApplication4\WpfRibbonApplication4\MainWindow.xaml.cs:line 90
at System.Threading.Tasks.Task.InnerInvoke()
at System.Threading.Tasks.Task.Execute()
InnerException:
非常感谢您的所有帮助。 我还有两个问题: 我用 Task.Factory.StartNew 稍微改写了我的代码。但是我的 Task2 似乎引起了问题。没有错误信息。看起来更像是一个紧密的循环。当然,我不知道为什么? 你会这么好心,并再次指出我正确的方向。 请记住,我已经做了大约 6 个月的 C# 和一周的 TPL,否则我不会再问你了。但是有了这么多经验... 再次感谢!
布莱恩密码:
var task1 = new Task(
(obj) =>
为什么需要obj?
private void Button1_Click(object sender, RoutedEventArgs e)
{
TaskScheduler uiTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext(); BlockingCollectionblockingCollection = new BlockingCollection(); CancellationTokenSource cts = new CancellationTokenSource();
CancellationToken token = cts.Token;
Task task1 = Task.Factory.StartNew(
() =>
{
for (int i = 0; i < 10 ; i++)
{
token.ThrowIfCancellationRequested();
string code = i++.ToString() + "\t" + AsyncHttpReq.get_source_WebRequest(uriDE);
blockingCollection.Add(code);
}
}, token, TaskCreationOptions.None, TaskScheduler.Default);
task1.ContinueWith(
(antecedents) =>
{
if (token.IsCancellationRequested)
{
TxtBlock2.Text = "Task cancel detected";
}
else
{
TxtBlock2.Text = "Signalling production end";
}
blockingCollection.CompleteAdding();
}, uiTaskScheduler);
Task task2 = Task.Factory.StartNew(
() =>
{
while (!blockingCollection.IsCompleted)
{
string dlcode;
if (blockingCollection.TryTake(out dlcode))
{
TxtBlock3.Text = dlcode;
}
}
}, token, TaskCreationOptions.None, uiTaskScheduler);
}
【问题讨论】:
-
你能粘贴完整的堆栈跟踪吗?另外,从 UI 线程调用的方法最初是否要启动?
-
是的,实际上它们是从 ui 线程启动的。这一切都在以下事件中声明: private void Button1_Click(object sender, RoutedEventArgs e) { } 我粘贴了上面的堆栈。
-
抱歉,您能粘贴完整的异常详细信息(即 exception.ToString())吗?这应该绝对有效。调用 Dispatcher.[Begin]Invoke 不是必需的。此外,您还有一个错误,如果取消工作,您将在非 UI 计划任务 (task1) 中设置 TextBlock2.Text。
-
我添加了它。我希望这是正确的堆栈跟踪。谢谢!
标签: c# .net wpf multithreading task-parallel-library