How to fix Task.Run from UI thread throwing STA error - c#

While I was refactoring some old C# code for document generation with the Office.Interop library, I found this and because of it was using UI context. When functions were called from it it was blocking it
For example:
private void btnFooClick(object sender, EventArgs e)
{
bool documentGenerated = chckBox.Checked ? updateDoc() : newDoc();
if(documentGenerated){
//do something
}
}
I decided to change it to reduce from blocking UI:
private async void btnFooClick(object sender, EventArgs e)
{
bool documentGenerated; = chckBox.Checked ? updateDoc() : newDoc();
if(chckBox.Checked)
{
documentGenerated = await Task.Run(() => updateDoc()).ConfigureAwait(false);
}
else
{
documentGenerated = await Task.Run(() => newDoc()).ConfigureAwait(false);
}
if(documentGenerated){
//do something
}
}
It was throwing this error:
Current thread must be set to single thread apartment (STA) mode
before OLE calls can be made
Why does it happen and what is the workaround?

The COM components accessed through Interop require the calling thread to be a STA thread but in your case it is not STA. Otherwise the STA component could be accessed through multiple threads. You can read more about why STA is required in Understanding and Using COM Threading Models.
You can make a extension method on Task class as suggested in Set ApartmentState on a Task to call the COM component through Interop using task:
public static Task<T> StartSTATask<T>(Func<T> func)
{
var tcs = new TaskCompletionSource<T>();
Thread thread = new Thread(() =>
{
try
{
tcs.SetResult(func());
}
catch (Exception e)
{
tcs.SetException(e);
}
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
return tcs.Task;
}
When you use Thread instead of task, you have to set the ApartmentState to STA using something like thread.SetApartmentState(ApartmentState.STA).

Because in this case Task presumably starts a new thread that isn't an STA thread. Your calls to updateDoc and newDoc are the ones that call the Interop layer, which doesn't like MTA threads.
You could refactor this to use Thread instead of Task and set the apartment to STA by yourself. I would be careful though, because I am not sure Interop likes multi-threading.

Related

How to wait until method complete in C#?

I have this C# code, it works but it won't wait until the method completed
foreach (var listBoxItem in visualListBox1.Items)
{
lblCursor.Text = "Processing.. " + listBoxItem;
Thread t = new Thread(() => extract_group(listBoxItem.ToString()));
t.IsBackground = false;
t.Name = "Group Scrapper";
t.Start();
}
How to wait until extract_group method is done before moving to the next listBoxItem?
I used t.join() but it made the UI unresponsive.
Using async/await helps you to not block main thread.
public async Task ExtractGroupAsync()
{
... (logic of the method)
... (you should use async methods here as well with await before executing those methods)
}
You execute this "ExtractGroup" task like:
var example = await ExtractGroupAsync();
It makes GUI unresponsive, because you are on GUI thread. Run whole code, in separate thread.
Note: when you want to access GUI elements from another thread, you should use invoke, for example:
t.Invoke(() => t.Name = "Group Scrapper");
If you want to stick with Thread I recommend using a WaitHandle e.g. AsyncManualResetEvent Class. This approach allows to make a thread wait without blocking CPU (e.g. spinlock).
Your provided example would become:
private static AsyncManualResetEvent mre = new AsyncManualResetEvent(false, true);
public async Task DoSomethingAsync(...)
{
foreach (var listBoxItem in visualListBox1.Items)
{
lblCursor.Text = "Processing.. " + listBoxItem;
Thread t = new Thread(() => ExtractGroup(listBoxItem.ToString()));
t.IsBackground = false;
t.Name = "Group Scrapper";
t.Start();
// Wait for signal to proceed without blocking resources
await mre.WaitAsync();
}
}
private void ExtractGroup(string groupName)
{
// Do something ...
// Signal handle to release all waiting threads (makes them continue).
// Subsequent calls to Set() or WaitOne() won't show effects until Rest() was called
mre.Set();
// Reset handle to make future call of WaitOne() wait again.
mre.Reset();
}
Another solution would be to go with the TPL and use Task instead of Thread:
public async Task DoWorkAsync()
{
foreach (var listBoxItem in visualListBox1.Items)
{
lblCursor.Text = "Processing.. " + listBoxItem;
// Wait for signal to proceed without blocking resources
await Task.Run(() => ExtractGroup(listBoxItem.ToString()));
}
}
The issue with your code sample is, that you are currently on the main thread, the UI thread. Calling Thread.Join() does what you think it does: it blocks the waiting thread until the running thread completes. But as mentioned, the waiting thread is the UI thread, so the UI becomes unresponsive and can even deadlock in some scenario. When you use async/await your invocations become asynchronous and hence awaitable without blocking the UI thread.

Classic never-ending thread loop using tasks?

Given is a very common threading scenario:
Declaration
private Thread _thread;
private bool _isRunning = false;
Start
_thread = new Thread(() => NeverEndingProc());
thread.Start();
Method
private void NeverEndingProc() {
while(_isRunning) {
do();
}
}
Possibly used in a asynchronous tcp listener that awaits callbacks until it gets stopped by letting the thread run out (_isRunning = false).
Now I'm wondering: Is it possible to do the same thing with Task? Using a CancellationToken? Or are Tasks only for procedures that are expected to end and report status?
You can certainly do this just by passing NeverEndingProc to Task.Run.
However, there is one important difference in functionality: if an exception is propagated out of NeverEndingProc in a bare Thread, it will crash the process. If it is in a Task, it will raise TaskScheduler.UnobservedException and then be silently ignored (as of .NET 4.5).
That said, there are alternatives you can explore. Reactive Extensions, for example, pretty much removes any need for the "infinite thread loop".
One reason to use Task + CancellationToken is to make the individual processes and their cancellation more independent of each other. In your example, notice how NeverEndingProc needs a direct reference to the _isRunning field in the same class. Instead, you could accept an external token:
Start:
public void StartNeverEndingProc(CancellationToken token) {
Task.Factory.StartNew(() => NeverEndingProc(token), token);
}
Method:
private void NeverEndingProc(CancellationToken token) {
while (true) {
token.ThrowIfCancellationRequested();
do();
}
}
Now cancellation is managed by the caller, and can be applied to multiple independent tasks:
var instance = new YourClass();
var cts = new CancellationTokenSource();
instance.StartNeverEndingProc(cts.Token); // start your task
StartOtherProc(cts.Token); // start another task
cts.Cancel(); // cancel both

Cancel Long Running task [duplicate]

In a thread, I create some System.Threading.Task and start each task.
When I do a .Abort() to kill the thread, the tasks are not aborted.
How can I transmit the .Abort() to my tasks ?
You can't. Tasks use background threads from the thread pool. Also canceling threads using the Abort method is not recommended. You may take a look at the following blog post which explains a proper way of canceling tasks using cancellation tokens. Here's an example:
class Program
{
static void Main()
{
var ts = new CancellationTokenSource();
CancellationToken ct = ts.Token;
Task.Factory.StartNew(() =>
{
while (true)
{
// do some heavy work here
Thread.Sleep(100);
if (ct.IsCancellationRequested)
{
// another thread decided to cancel
Console.WriteLine("task canceled");
break;
}
}
}, ct);
// Simulate waiting 3s for the task to complete
Thread.Sleep(3000);
// Can't wait anymore => cancel this task
ts.Cancel();
Console.ReadLine();
}
}
Like this post suggests, this can be done in the following way:
int Foo(CancellationToken token)
{
Thread t = Thread.CurrentThread;
using (token.Register(t.Abort))
{
// compute-bound work here
}
}
Although it works, it's not recommended to use such approach. If you can control the code that executes in task, you'd better go with proper handling of cancellation.
Aborting a Task is easily possible if you capture the thread in which the task is running in. Here is an example code to demonstrate this:
void Main()
{
Thread thread = null;
Task t = Task.Run(() =>
{
//Capture the thread
thread = Thread.CurrentThread;
//Simulate work (usually from 3rd party code)
Thread.Sleep(1000);
//If you comment out thread.Abort(), then this will be displayed
Console.WriteLine("Task finished!");
});
//This is needed in the example to avoid thread being still NULL
Thread.Sleep(10);
//Cancel the task by aborting the thread
thread.Abort();
}
I used Task.Run() to show the most common use-case for this - using the comfort of Tasks with old single-threaded code, which does not use the CancellationTokenSource class to determine if it should be canceled or not.
This sort of thing is one of the logistical reasons why Abort is deprecated. First and foremost, do not use Thread.Abort() to cancel or stop a thread if at all possible. Abort() should only be used to forcefully kill a thread that is not responding to more peaceful requests to stop in a timely fashion.
That being said, you need to provide a shared cancellation indicator that one thread sets and waits while the other thread periodically checks and gracefully exits. .NET 4 includes a structure designed specifically for this purpose, the CancellationToken.
I use a mixed approach to cancel a task.
Firstly, I'm trying to Cancel it politely with using the Cancellation.
If it's still running (e.g. due to a developer's mistake), then misbehave and kill it using an old-school Abort method.
Checkout an example below:
private CancellationTokenSource taskToken;
private AutoResetEvent awaitReplyOnRequestEvent = new AutoResetEvent(false);
void Main()
{
// Start a task which is doing nothing but sleeps 1s
LaunchTaskAsync();
Thread.Sleep(100);
// Stop the task
StopTask();
}
/// <summary>
/// Launch task in a new thread
/// </summary>
void LaunchTaskAsync()
{
taskToken = new CancellationTokenSource();
Task.Factory.StartNew(() =>
{
try
{ //Capture the thread
runningTaskThread = Thread.CurrentThread;
// Run the task
if (taskToken.IsCancellationRequested || !awaitReplyOnRequestEvent.WaitOne(10000))
return;
Console.WriteLine("Task finished!");
}
catch (Exception exc)
{
// Handle exception
}
}, taskToken.Token);
}
/// <summary>
/// Stop running task
/// </summary>
void StopTask()
{
// Attempt to cancel the task politely
if (taskToken != null)
{
if (taskToken.IsCancellationRequested)
return;
else
taskToken.Cancel();
}
// Notify a waiting thread that an event has occurred
if (awaitReplyOnRequestEvent != null)
awaitReplyOnRequestEvent.Set();
// If 1 sec later the task is still running, kill it cruelly
if (runningTaskThread != null)
{
try
{
runningTaskThread.Join(TimeSpan.FromSeconds(1));
}
catch (Exception ex)
{
runningTaskThread.Abort();
}
}
}
To answer Prerak K's question about how to use CancellationTokens when not using an anonymous method in Task.Factory.StartNew(), you pass the CancellationToken as a parameter into the method you're starting with StartNew(), as shown in the MSDN example here.
e.g.
var tokenSource = new CancellationTokenSource();
var token = tokenSource.Token;
Task.Factory.StartNew( () => DoSomeWork(1, token), token);
static void DoSomeWork(int taskNum, CancellationToken ct)
{
// Do work here, checking and acting on ct.IsCancellationRequested where applicable,
}
You should not try to do this directly. Design your tasks to work with a CancellationToken, and cancel them this way.
In addition, I would recommend changing your main thread to function via a CancellationToken as well. Calling Thread.Abort() is a bad idea - it can lead to various problems that are very difficult to diagnose. Instead, that thread can use the same Cancellation that your tasks use - and the same CancellationTokenSource can be used to trigger the cancellation of all of your tasks and your main thread.
This will lead to a far simpler, and safer, design.
Tasks have first class support for cancellation via cancellation tokens. Create your tasks with cancellation tokens, and cancel the tasks via these explicitly.
You can use a CancellationToken to control whether the task gets cancelled. Are you talking about aborting it before it's started ("nevermind, I already did this"), or actually interrupting it in middle? If the former, the CancellationToken can be helpful; if the latter, you will probably need to implement your own "bail out" mechanism and check at appropriate points in the task execution whether you should fail fast (you can still use the CancellationToken to help you, but it's a little more manual).
MSDN has an article about cancelling Tasks:
http://msdn.microsoft.com/en-us/library/dd997396.aspx
Task are being executed on the ThreadPool (at least, if you are using the default factory), so aborting the thread cannot affect the tasks. For aborting tasks, see Task Cancellation on msdn.
I tried CancellationTokenSource but i can't do this. And i did do this with my own way. And it works.
namespace Blokick.Provider
{
public class SignalRConnectProvider
{
public SignalRConnectProvider()
{
}
public bool IsStopRequested { get; set; } = false; //1-)This is important and default `false`.
public async Task<string> ConnectTab()
{
string messageText = "";
for (int count = 1; count < 20; count++)
{
if (count == 1)
{
//Do stuff.
}
try
{
//Do stuff.
}
catch (Exception ex)
{
//Do stuff.
}
if (IsStopRequested) //3-)This is important. The control of the task stopping request. Must be true and in inside.
{
return messageText = "Task stopped."; //4-) And so return and exit the code and task.
}
if (Connected)
{
//Do stuff.
}
if (count == 19)
{
//Do stuff.
}
}
return messageText;
}
}
}
And another class of the calling the method:
namespace Blokick.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MessagePerson : ContentPage
{
SignalRConnectProvider signalR = new SignalRConnectProvider();
public MessagePerson()
{
InitializeComponent();
signalR.IsStopRequested = true; // 2-) And this. Make true if running the task and go inside if statement of the IsStopRequested property.
if (signalR.ChatHubProxy != null)
{
signalR.Disconnect();
}
LoadSignalRMessage();
}
}
}
You can abort a task like a thread if you can cause the task to be created on its own thread and call Abort on its Thread object. By default, a task runs on a thread pool thread or the calling thread - neither of which you typically want to abort.
To ensure the task gets its own thread, create a custom scheduler derived from TaskScheduler. In your implementation of QueueTask, create a new thread and use it to execute the task. Later, you can abort the thread, which will cause the task to complete in a faulted state with a ThreadAbortException.
Use this task scheduler:
class SingleThreadTaskScheduler : TaskScheduler
{
public Thread TaskThread { get; private set; }
protected override void QueueTask(Task task)
{
TaskThread = new Thread(() => TryExecuteTask(task));
TaskThread.Start();
}
protected override IEnumerable<Task> GetScheduledTasks() => throw new NotSupportedException(); // Unused
protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued) => throw new NotSupportedException(); // Unused
}
Start your task like this:
var scheduler = new SingleThreadTaskScheduler();
var task = Task.Factory.StartNew(action, cancellationToken, TaskCreationOptions.LongRunning, scheduler);
Later, you can abort with:
scheduler.TaskThread.Abort();
Note that the caveat about aborting a thread still applies:
The Thread.Abort method should be used with caution. Particularly when you call it to abort a thread other than the current thread, you do not know what code has executed or failed to execute when the ThreadAbortException is thrown, nor can you be certain of the state of your application or any application and user state that it is responsible for preserving. For example, calling Thread.Abort may prevent static constructors from executing or prevent the release of unmanaged resources.
You can use this class..:
It works for all typs of returned Values..
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace CarNUChargeTester
{
public class TimeOutTaskRunner<T>
{
private Func<T> func;
private int sec;
private T result;
public TimeOutTaskRunner(Func<T> func, int sec)
{
this.func = func;
this.sec = sec;
}
public bool run()
{
var scheduler = new SingleThreadTaskScheduler();
Task<T> task = Task<T>.Factory.StartNew(func, (new CancellationTokenSource()).Token, TaskCreationOptions.LongRunning, scheduler);
if (!task.Wait(TimeSpan.FromSeconds(sec)))
{
scheduler.TaskThread.Abort();
return false;
}
result = task.Result;
return true;
}
public T getResult() { return result; }
}
class SingleThreadTaskScheduler : TaskScheduler
{
public Thread TaskThread { get; private set; }
protected override void QueueTask(Task task)
{
TaskThread = new Thread(() => TryExecuteTask(task));
TaskThread.Start();
}
protected override IEnumerable<Task> GetScheduledTasks() => throw new NotSupportedException();
protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued) => throw new NotSupportedException();
}
}
To use it you can write:
TimeOutTaskRunner<string> tr = new TimeOutTaskRunner<string>(f, 10); // 10 sec to run f
if (!tr.run())
errorMsg("TimeOut"); !! My func
tr.getResult() // get the results if it done without timeout..

Multi-Threading a Large C# Application Using async/await

All, I have been given the job to multi-thread a large C# application. To do this I have chosen to go use async/await. I am well aware of the use of IProgress<T> to report progress to the UI (let’s call this 'pushing' information to the UI), but I also need to 'pull' data from the UI (in my case a SpreadsheetGear workbook, which contains data). It is this two-way interaction that I want some advice on...
Currently I fire a click event to start the processing, and the code has the following structure:
CancellationTokenSource cancelSource;
private async void SomeButton_Click(object sender, EventArgs e)
{
// Set up progress reporting.
IProgress<CostEngine.ProgressInfo> progressIndicator =
new Progress<CostEngine.ProgressInfo>();
// Set up cancellation support, and UI scheduler.
cancelSource = new CancellationTokenSource();
CancellationToken token = cancelSource.Token;
TaskScheduler UIScheduler = TaskScheduler.FromCurrentSynchronizationContext();
// Run the script processor async.
CostEngine.ScriptProcessor script = new CostEngine.ScriptProcessor(this);
await script.ProcessScriptAsync(doc, progressIndicator, token, UIScheduler);
// Do stuff in continuation...
...
}
Then in ProcessScriptAsync, I have the following:
public async Task ProcessScriptAsync(
SpreadsheetGear.Windows.Forms.WorkbookView workbookView,
IProgress<ProgressInfo> progressInfo,
CancellationToken token,
TaskScheduler UIScheduler)
{
// This is still on the UI thread.
// Here do some checks on the script workbook on the UI thread.
try
{
workbookView.GetLock();
// Now perform tests...
}
finally { workbookView.ReleaseLock(); }
// Set the main processor off on a background thread-pool thread using await.
Task<bool> generateStageTask = null;
generateStageTask = Task.Factory.StartNew<bool>(() =>
GenerateStage(workbookView,
progressInfo,
token,
UIScheduler));
bool bGenerationSuccess = await generateStageTask;
// Automatic continuation back on UI thread.
if (!bGenerationSuccess) { // Do stuff... }
else {
// Do other stuff
}
}
This, so far, seems fine. The problem I now have is in the method GenerateStage, which is now run on a background thread-pool thread
private bool GenerateStage(
SpreadsheetGear.WorkbookView workbookView,
IProgress<ProgressInfo> progressInfo,
CancellationToken token,
TaskScheduler scheduler)
{
...
// Get the required data using the relevant synchronisation context.
SpreadsheetGear.IWorksheet worksheet = null;
SpreadsheetGear.IRange range = null;
Task task = Task.Factory.StartNew(() =>
{
worksheet = workbookView.ActiveWorksheet;
range = worksheet.UsedRange;
}, CancellationToken.None,
TaskCreationOptions.None,
scheduler);
try
{
task.Wait();
}
finally
{
task.Dispose();
}
// Now perform operations with 'worksheet'/'range' on the thread-pool thread...
}
In this method I need to pull data from the UI and write data to the UI many times. For the writing I can clearly use 'progressInfo', but how to handle the pulling information from the UI. Here, I have used the UI thread synchronisation context, but this will be done many times. Is there a better way to perform these operations/are there any flaws in my current approach?
Note. Clearly I would wrap the Task.Factory.StartNew(...) code up into a reusable method, the above is shown explicitly for breivity.
If you're constantly going back and forth between UI and thread pool threads, your code is going to be a bit messy.
You essentially have two options: have your "normal" context be the thread pool thread with portions scheduled to the UI thread (as you have it now), or have your "normal" context be the UI thread with portions scheduled to a thread pool thread.
I usually prefer the latter, since you can use the simpler Task.Run instead of Task.Factory.StartNew on a specific TaskScheduler. But either way, the code is going to be a bit messy.
I didn't work with SpreadsheetGear workbook, but I suppose that it has an event mechanism which you could use for storing relevant data for you in a custom object which you can access from the outside of the UISynchronizationContext, in this way you avoid to be strongly bounded to the workbook UI control. This will permit you to avoid blocking UI thread with
Task task = Task.Factory.StartNew(() =>
{
worksheet = workbookView.ActiveWorksheet;
range = worksheet.UsedRange;
}, CancellationToken.None,
TaskCreationOptions.None,
scheduler);
try
{
task.Wait();
}
finally
{
task.Dispose();
}
part from the GenerateStage method.
But again, my suggestion is based on some assumptions about SpreadsheetGear workbook controls, that can be incorrect.

How to create a task (TPL) running a STA thread?

Using Thread is pretty straightforward
Thread thread = new Thread(MethodWhichRequiresSTA);
thread.SetApartmentState(ApartmentState.STA);
How to accomplish the same using Tasks in a WPF application? Here is some code:
Task.Factory.StartNew
(
() =>
{return "some Text";}
)
.ContinueWith(r => AddControlsToGrid(r.Result));
I'm getting an InvalidOperationException with
The calling thread must be STA, because many UI components require this.
You can use the TaskScheduler.FromCurrentSynchronizationContext Method to get a TaskScheduler for the current synchronization context (which is the WPF dispatcher when you're running a WPF application).
Then use the ContinueWith overload that accepts a TaskScheduler:
var scheduler = TaskScheduler.FromCurrentSynchronizationContext();
Task.Factory.StartNew(...)
.ContinueWith(r => AddControlsToGrid(r.Result), scheduler);
Dispatcher.Invoke could be a solution. e.g.
private async Task<bool> MyActionAsync()
{
// await for something, then return true or false
}
private void StaContinuation(Task<bool> t)
{
myCheckBox.IsChecked = t.Result;
}
private void MyCaller()
{
MyActionAsync().ContinueWith((t) => Dispatcher.Invoke(() => StaContinuation(t)));
}

Categories

Resources