TPLとWPfを初めて使用していて、次の問題があります。 無限ループ(ここではforループのみ)でサイトをダウンロードしようとしており、 をキューに追加しようとしています。次のタスクはそれを取り出し、それをTextblockに表示します。 しかし、私は適切なTaskSchedulerを使用すると思うが、私はUIのために正しいスレッドを取得していないようだ。WPF、TPL、プロデューサ/コンシューマパターン - 間違ったスレッドエラー
ありがとうございました!
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
[マネージド移行にネイティブ]バイト0x2d System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()+WpfRibbonApplication4.exe!WpfRibbonApplication4.MainWindow.Button1_Click.AnonymousMethod__4(オブジェクトOBJ)線83 + 0x16バイトC# のMscorlib.dll!System.Threading.Tasks.Task.InnerInvoke()+ 0x44のバイト mscorlib.dll!System.Threading.Tasks.Task.Execute()+ 0x43 bytes mscorlib.dll!System.Threading.Tasks.Task.ExecutionContextCallback(オブジェクトobj)+ 0x27バイト
mscorlib.dll!System.Threading.ExecutionContext .Run(System.Threading.ExecutionContext executionContext、System.Threading.ContextCallbackコールバック、オブジェクト状態、bool ignoreSyncCtx)+ 0xb0バイト
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.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:
ご協力いただきありがとうございます。 私はまだ2つの質問があります。 Task.Factory.StartNewでコードを少し書き直しました。しかし、私のTask2は問題を引き起こすようです。エラーメッセージはありません。むしろタイトなループのようです。もちろん、私は理由を理解できませんでしたか? あなたはとても親切で、私を正しい方向に向けるでしょうか。 私は6ヶ月間C#をやっていて、1週間はTPLしなければ、もう一度聞いてみません。しかし、この量の経験... もう一度ありがとう!
ブライアンコード:
var task1 = new Task(
(obj) =>
はなぜobj
が必要とされていますか?
private void Button1_Click(object sender, RoutedEventArgs e)
{
TaskScheduler uiTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext()。BlockingCollection blockingCollection = 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(オブジェクト送信者、RoutedEventArgs e)の {} 私は上記のスタックを貼り付けました。 – user774326
申し訳ありませんが、完全な例外の詳細(つまりexception.ToString())を貼り付けることはできますか?これは絶対に機能するはずです。ディスパッチャを呼び出す[Begin]呼び出しは必要ありません。また、作業がキャンセルされた場合、UI以外のスケジュールされたタスク(task1)にTextBlock2.Textを設定するバグがあります。 –