locked
Concurrency task class is blocking my main thread

    Question

  • Hey, I have two questions, I wrote this simple code below to read an XML from the project. I added sleep for debugging purposes and it looks like my main function returns 15 secs later. I thought task::then method is executing the continuation and the async method in different thread. Can anyone explain why I am seeing such behavior?

    Another thing is that if I put .wait() to the last task, I'm seeing a crash that I didn't understand why it's crashing. It's not throwing Exception^ type, I am able to catch it with catch(...) operator.

    				StorageFolder^ root_folder = Windows::ApplicationModel::Package::Current->InstalledLocation;
    			
    				task<StorageFolder^>  get_folder_task(root_folder->GetFolderAsync(package_folder));
    				
    				get_folder_task.then([this](StorageFolder^ folder_locator) -> IAsyncOperation<StorageFile^>^
    				{
    					concurrency::wait(5000);
    					return folder_locator->GetFileAsync(file_name_);
    				}).then([](task<StorageFile^> file) ->  IAsyncOperation<XmlDocument^>^
    				{
    					concurrency::wait(5000);
    					return XmlDocument::LoadFromFileAsync(file.get());
    				}).then([this](task<XmlDocument^> doc)
    				{
    					concurrency::wait(5000);
    					doc_ = doc.get();
    				});  // if I put .wait here, it crashes.

    Wednesday, March 07, 2012 6:10 AM

Answers

  • Hi Emre Kanlikilicer,

    It is invalid by design to call task<>.wait / .get() on an STA thread because it can hang.

    The continuations execute as expected,
    Please find the following code.

    Case 1:
    • When an IAsync object is created on ASTA it is bound to that apartment, and concurrency runtime marshal calls to that ASTA thread.
    • Concurrency::wait() doesn’t process UI messages, so the text output is delayed until no more continuations are executing
    Case 2:
    • Creating an IAsync on Concurrency runtime thread doesn’t bound it to ASTA threads
    • UI thread update the text instantly

     sample output:

    Button_Click_2 : 2293750
    IAsync : 2298750
    cont 1 : 2303765
    cont 2 : 2308765
    cont 3 : 2313781

    template<class DELAY_FUNC>
    void
    TestContinuations(CppApplication::BlankPage^ thisPage, DELAY_FUNC func)
    {
        task<int>  get_folder_task(
            create_async([=]()
        {
            func();
            thisPage->log( "IAsync : " + GetTickCount64().ToString() );
            return 0;
        }));
        
        get_folder_task.then([=](int cont0)
        {
            func();
            thisPage->log( "cont 1 : " + GetTickCount64().ToString() );
            return 1;
        }).then([=](int cont1)
        {
            func();
            thisPage->log( "cont 2 : " + GetTickCount64().ToString() );
            return 2;
        }).then([=](int cont2)
        {
            func();
            thisPage->log( "cont 3 : " + GetTickCount64().ToString() );
        });  // if I put .wait here, it crashes.
    }
    
    void CppApplication::BlankPage::Case_1(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
    {
        TestContinuations(this, []()
        { 
            Concurrency::wait(5000); 
        });
        log( "Button_Click_2 : " + GetTickCount64().ToString() );
    }
    
    void CppApplication::BlankPage::Case_2(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
    {
        task<void> t([this]()
        {
            TestContinuations(this, []()
            { 
                Concurrency::wait(5000); 
            });
        });
        log( "Button_Click_2 : " + GetTickCount64().ToString() );
    }
    
    void BlankPage::log( String^ content )
    {
        this->Dispatcher->InvokeAsync(Windows::UI::Core::CoreDispatcherPriority::Normal,
            ref new Windows::UI::Core::InvokedHandler(
                [=](Object^ obj, Windows::UI::Core::InvokedHandlerArgs^ args)
                {
                    txtMessages->Text += "\r\n" + content;
                }), this, nullptr);
    }
    


    mameen

    Friday, March 09, 2012 6:01 PM

All replies

  • Have you had a found this document Asynchronous programming in C++? If I understand your description correctly the section entitled Creating a chain of tasks explains the expected behavior.

    Regarding the crash you mention, is it possibly a Concurrency::invalid_operation of some type you're encountering?


    David Lamb

    Thursday, March 08, 2012 2:10 AM
    Moderator
  • Hi Emre Kanlikilicer,

    It is invalid by design to call task<>.wait / .get() on an STA thread because it can hang.

    The continuations execute as expected,
    Please find the following code.

    Case 1:
    • When an IAsync object is created on ASTA it is bound to that apartment, and concurrency runtime marshal calls to that ASTA thread.
    • Concurrency::wait() doesn’t process UI messages, so the text output is delayed until no more continuations are executing
    Case 2:
    • Creating an IAsync on Concurrency runtime thread doesn’t bound it to ASTA threads
    • UI thread update the text instantly

     sample output:

    Button_Click_2 : 2293750
    IAsync : 2298750
    cont 1 : 2303765
    cont 2 : 2308765
    cont 3 : 2313781

    template<class DELAY_FUNC>
    void
    TestContinuations(CppApplication::BlankPage^ thisPage, DELAY_FUNC func)
    {
        task<int>  get_folder_task(
            create_async([=]()
        {
            func();
            thisPage->log( "IAsync : " + GetTickCount64().ToString() );
            return 0;
        }));
        
        get_folder_task.then([=](int cont0)
        {
            func();
            thisPage->log( "cont 1 : " + GetTickCount64().ToString() );
            return 1;
        }).then([=](int cont1)
        {
            func();
            thisPage->log( "cont 2 : " + GetTickCount64().ToString() );
            return 2;
        }).then([=](int cont2)
        {
            func();
            thisPage->log( "cont 3 : " + GetTickCount64().ToString() );
        });  // if I put .wait here, it crashes.
    }
    
    void CppApplication::BlankPage::Case_1(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
    {
        TestContinuations(this, []()
        { 
            Concurrency::wait(5000); 
        });
        log( "Button_Click_2 : " + GetTickCount64().ToString() );
    }
    
    void CppApplication::BlankPage::Case_2(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
    {
        task<void> t([this]()
        {
            TestContinuations(this, []()
            { 
                Concurrency::wait(5000); 
            });
        });
        log( "Button_Click_2 : " + GetTickCount64().ToString() );
    }
    
    void BlankPage::log( String^ content )
    {
        this->Dispatcher->InvokeAsync(Windows::UI::Core::CoreDispatcherPriority::Normal,
            ref new Windows::UI::Core::InvokedHandler(
                [=](Object^ obj, Windows::UI::Core::InvokedHandlerArgs^ args)
                {
                    txtMessages->Text += "\r\n" + content;
                }), this, nullptr);
    }
    


    mameen

    Friday, March 09, 2012 6:01 PM