I'd like to execute some code in a background thread, and have the background code periodically execute code on the main thread. Something like the following:
void functionThatMustBeRunOnMainThread(string arg) {
Debug.Print("On main thread: "+arg);
}
// Run the task asynchronously. On completion, call completionAction in the main thread.
void launchAsyncBackgroundTask( Action<bool> completionAction ) {
performInArbitraryBackgroundThread(() => {
// do first long running thing
sleep(10);
// notify main thread
performOnMainThread(() => {
functionThatMustBeRunOnMainThread("phase 1");
});
// do second long running thing
sleep(10);
// notify main thread
performOnMainThread(() => {
functionThatMustBeRunOnMainThread("phase 2");
});
// do final long running thing
sleep(10);
performOnMainThread(() => {
Debug.Print("Done!");
completionAction(true);
});
});
}
I know about BackgroundWorker
but it doesn't offer the flexibility I'm looking for.
There's two points here -
This is trivial to do in Obj-C using Grand Central Dispatch (it pretty much works as above). Is there a C# equivalent?
You can achieve what you need quite easily using async-await
along with the Task Parallel Library
:
This example assumes that your MethodThatDoesStuffInBackground
or any of the other time-consuming methods are CPU bound operations. If not and they're doing IO, you can drop the use of Task.Run
:
(This method should be called from the UI thread in order to work properly)
public async Task DoStuff()
{
await Task.Run(() => MethodThatDoesStuffInBackground());
FunctionThatMustRunOnMainThread();
await Task.Run(() => MethodThatDoesMoreStuffInBackground());
FunctionThatMustRunOnMainThread();
await Task.Run(() => EvenMoreWorkInBackgroundThread());
FunctionThatMustRunOnMainThread();
}
I recommend using Task.Run
for background work, IProgress<T>
for progress updates, and Task
for completion notification. This approach enables you to keep your background logic in one place, separate from the UI.
Something like this:
// Run the task asynchronously. On completion, call completionAction in the main thread.
async Task launchBackgroundTaskAsync( Action<bool> completionAction ) {
var progress = new Progress<string>(arg => {
Debug.Print("On main thread: "+arg);
};
await Task.Run(() => BackgroundLogic(progress));
completionAction(true);
}
void BackgroundLogic(IProgress<string> progress) {
// do first long running thing
sleep(10);
// notify main thread
if (progress != null)
progress.Report("phase 1");
// do second long running thing
sleep(10);
// notify main thread
if (progress != null)
progress.Report("phase 2");
// do final long running thing
sleep(10);
if (progress != null)
progress.Report("Done!");
}
Note that the completionAction
is no longer necessary, since launchBackgroundTaskAsync
itself returns a Task
. It can simply be removed without any loss of capability - just have the callers of this method use await
:
async Task launchBackgroundTaskAsync() {
var progress = new Progress<string>(arg => {
Debug.Print("On main thread: "+arg);
};
await Task.Run(() => BackgroundLogic(progress));
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.