Possible Duplicate:
How to create a task (TPL) running a STA thread?
I'm using the following code:
var task = Task.Factory.StartNew<List<NewTwitterStatus>>(
() => GetTweets(securityKeys),
TaskCreationOptions.LongRunning);
Dispatcher.BeginInvoke(DispatcherPriority.Background,
new Action(() =>
{
var result = task.Result; // ERROR!!! The calling thread cannot access this object because a different thread owns it.
RecentTweetList.ItemsSource = result;
Visibility = result.Any() ? Visibility.Visible : Visibility.Hidden;
}));
And I'm getting the error:
var result = task.Result; // ERROR!!! The calling thread cannot access this object because a different thread owns it.
What do I need to do to resolve this problem?
Task Scheduler successfully finished the "%3" instance of the "%1" task for user "%2". This event is logged when the task scheduler successfully finished the instances of the task user and the history of a task is tracked by events. This is an information event and no user action is required.
I reached out to Microsoft To Do Support on November 25th, 2019 and received the following response on November 26th, 2019: Thank you for letting us know about this. Our apologies for the trouble. We're aware of this issue and are working on a fix. A lot of other users also reported that recurring tasks are creating duplicate entries.
The issue may occur when “a continuation” (*) of a task, backed by TaskCompletionSource<T>, blocks the thread in one way or another, thereby blocking a thread that calls SetResult. (*) As we’ll see in a moment different types of continuations behave differently. The main challenge with such issues that it’s very hard to understand the root cause.
If you can’t control a task’s creation but want to run the continuations asynchronously you can explicitly call Task.Yield()right after awaitor switch to custom tasks altogether (which is hardly an option). But if you can, you should provide task creation options every time you use TaskCompletionSource<T>:
The idea of Tasks is that you can chain them:
var task = Task.Factory.StartNew<List<NewTwitterStatus>>(
() => GetTweets(securityKeys),
TaskCreationOptions.LongRunning
)
.ContinueWith(tsk => EndTweets(tsk) );
void EndTweets(Task<List<string>> tsk)
{
var strings = tsk.Result;
// now you have your result, Dispatchar Invoke it to the Main thread
}
You need to move the Dispatcher call into the task continuation which would look something like this:
var task = Task.Factory
.StartNew<List<NewTwitterStatus>>(() => GetTweets(securityKeys), TaskCreationOptions.LongRunning)
.ContinueWith<List<NewTwitterStatus>>(t =>
{
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background,
new Action(() =>
{
var result = t.Result;
RecentTweetList.ItemsSource = result;
Visibility = result.Any() ? Visibility.Visible : Visibility.Hidden;
}));
},
CancellationToken.None,
TaskContinuationOptions.None);
It looks like you are starting a background task to start reading tweets, then starting another task to read the result without any co-ordination between the two.
I would expect your task to have another task in a continuation (see http://msdn.microsoft.com/en-us/library/dd537609.aspx) and in the continuation you may need to invoke back to the UI thread....
var getTask = Task.Factory.StartNew(...);
var analyseTask = Task.Factory.StartNew<...>(
()=>
Dispatcher.Invoke(RecentTweetList.ItemsSource = getTask.Result));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With