Reputation: 321
I'm writing some code that is invoked on the UI thread, invokes some code on another thread (not the ThreadPool, but the same thread each time), and then resumes on the UI thread. I'd like some advice on the best async way to do this.
The complexity of the EnsureThread method is because the other thread must be the same thread every time and must be STA with a Dispatcher running on it. This is because I need to use MCI, but do not want it running on the UI thread. See here https://stackoverflow.com/a/32711239/420159.
I create the second thread like so:
private static void EnsureThread()
{
if (eventLoopThread != null)
{
return;
}
lock (eventLoopLock)
{
if (eventLoopThread == null)
{
var lck = new EventWaitHandle(false, EventResetMode.ManualReset);
var t = new Thread(() =>
{
try
{
// create dispatcher and sync context
var d = Dispatcher.CurrentDispatcher;
var context = new DispatcherSynchronizationContext(d);
SynchronizationContext.SetSynchronizationContext(context);
// create taskfactory
eventLoopFactory = new TaskFactory(TaskScheduler.FromCurrentSynchronizationContext());
eventLoopDispatcher = d;
}
finally
{
lck.Set();
}
// run the event loop
Dispatcher.Run();
});
t.SetApartmentState(ApartmentState.STA);
t.IsBackground = true;
t.Start();
lck.WaitOne();
lck.Dispose();
eventLoopThread = t;
}
}
}
and then I call the second thread like so:
async void button_click(...)
{
// do something 1
await eventLoopFactory.StartNew(()=>
{
// do something 2
});
// do something 3
}
Is there a better way to do it?
Upvotes: 2
Views: 133
Reputation: 9723
Your Button_Click
already seems to be doing way too many things, you should first split this method into separate methods.
async void Button_Click(...)
{
await DoSomething1();
await DoSomething2();
await DoSomething3();
}
Now, your other methods will look something like this:
async Task DoSomething1()
{
await Task.Run(() =>
{
...
});
}
This will allow your Button_Click
method to asynchronously perform these tasks (in order) and keep your UI responsive.
Upvotes: 1
Reputation: 2509
You don't really need to use a thread factory if you want to run a delegate on a thread of the ThreadPool
just use
await Task.Run(() =>
{
// do something 2
});
That way, you don't need to run your // do something
code on an event loop thread, but it will be run on an available thread from the thread pool.
You shouldn't create a second thread yourself. Thread pools are the right tool for that, as it will recycle idle threads in a very efficient way.
Upvotes: 4