Mattias Johansson
Mattias Johansson

Reputation: 131

Task Parallel Library Task.ContinueWith using C++/CLI

I have started using Task Parallel Library (TPL) in my C++/CLI project. This works well when running simple tasks which can be run independently. The software that I'm writing has the ability to check for updates on a server. This was previously done on the main thread of the but this made the GUI freeze for the duration of the check which really doesn't give a good impression of the software for the user.

I have therefore tested with using TPL to run the check. I can start the check for updates (following the directions from Using .NET (3.5) Task Parallel Library in C++/ CLI) like this:

Void SoftwareUpdateChecker::RunCheck(Boolean automatic)
{
    Task<Boolean>^ versionCheckTask = Task<Boolean>::Factory->StartNew( gcnew Func<Boolean>(this, &SoftwareUpdateChecker::IsUpdateAvailable) );

    // This line is the problem, this freezes the main thread...
    versionCheckTask->Wait();

    Boolean isNewerVersionOnServer = versionCheckTask->Result;

    if(isNewerVersionOnServer)
    {
        QueryUserToDownloadNewVersion();
    }
}

TPL has the nice feature of making it possible to define the order of tasks using Task.ContinueWith(...) as outlined in Task chaining (wait for the previous task to completed). What I want to do is (in C#):

Task.Factory.StartNew( () => IsUpdateAvailable())
   .ContinueWith(() => OnVersionCheckDone(antecendent.Result), 
       TaskScheduler.FromCurrentSynchronizationContext());

Where OnVersionCheckDone(bool) can take care of asking the user how to proceed if there is indeed a new version available. All examples for how to do this are written in C# and I have not been able to convert this into C++/CLI.

Is this at all possible ?

Upvotes: 2

Views: 2517

Answers (1)

Brain2000
Brain2000

Reputation: 4894

While C++ does not support managed lambdas, you can do a little fanagling to get delegates to work, and cover your own variables when necessary. In this case, the ContinueWith delegate takes a Task as an argument, so we don't have to do too much.

Void SoftwareUpdateChecker::RunCheck(Boolean automatic)
{
    Task<Boolean>^ versionCheckTask = Task<Boolean>::Factory->StartNew( gcnew Func<Boolean>(this, &SoftwareUpdateChecker::IsUpdateAvailable) );
    versionCheckTask->ContinueWith(gcnew Action<Task<Boolean>^>(this, &SoftwareUpdateChecker::OnVersionCheckDone), TaskScheduler::FromCurrentSynchronizationContext());
}

Void SoftwareUpdateChecker::OnVersionCheckDone(Task<Boolean>^ versionCheckTask)
{
    if(versionCheckTask->Result) QueryUserToDownloadNewVersion();
}

Upvotes: 2

Related Questions