14

Windows ストア アプリでは、C++ (C# は似ていますが)、次のようなことを行います。

IAsyncAction^ Action = CurrentAppSimulator::ReloadSimulatorAsync(proxyFile);
create_task( Action ).then([this]()
{
}.wait();

未処理の例外が発生します。通常は

Microsoft C++ exception: Concurrency::invalid_operation at memory location 0x0531eb58

そして、それを使用しようとする前に、アプリ内購入情報を取得するために、そのアクションを完了する必要があります。ここで奇妙なのは、IAsyncAction 以外のものは問題なく待機することです。IAsyncOperation と IAsyncOperationWithProgress は問題なく機能しましたが、これは ? 例外が発生し、その後クラッシュします。

正直なところ、IAsyncOperation と IAsyncAction の違いがわかりません。私には似ているように思えます。

更新

このページhttp://msdn.microsoft.com/en-us/library/vstudio/hh750082.aspxを分析すると、IAsyncAction が戻り値の型のない単なる IAsyncOperation であることがわかります。しかし、ほとんどの IAsyncAction-s が待機可能であることがわかります。ただし、実際の問題は、特定の Windows 関数が (何らかの理由で) 特定のスレッドで実行されることです。ReloadSimulatorAsync はその良い例の 1 つです。

次のようなコードを使用します。

void WaitForAsync( IAsyncAction ^A )
{   
    while(A->Status == AsyncStatus::Started)
    {
        std::chrono::milliseconds milis( 1 );
        std::this_thread::sleep_for( milis );
    }   
    AsyncStatus S = A->Status;  
}

無限ループになります。他の関数で呼び出された場合、実際に機能します。ここでの問題は、すべてが Async の場合、特定のスレッドでタスクを実行する必要があるのはなぜですか? Async の代わりに、RunOn(Main/UI)Thread などにする必要があります。

解決済み、回答を参照してください。

4

4 に答える 4

6

これは仕事を成し遂げる魔法の修正です:

void WaitForAsync( IAsyncAction ^A )
{   
    while(A->Status == Windows::Foundation::AsyncStatus::Started)
    {   
        CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent);                     
    }

    Windows::Foundation::AsyncStatus S = A->Status; 
}
于 2013-11-17T16:48:12.343 に答える
2

一般に、アダムの答えが言うように、ブロックではなく、継続 (.then(...)) を使用する必要があります。しかし、何らかの理由で (コードをテストするために) 待機したい場合は、最後の継続からイベントをトリガーできます (C# の用語を使用するため):

    TEST_METHOD(AsyncOnThreadPoolUsingEvent)
    {

        std::shared_ptr<Concurrency::event> _completed = std::make_shared<Concurrency::event>();


        int i;

        auto workItem = ref new WorkItemHandler(
            [_completed, &i](Windows::Foundation::IAsyncAction^ workItem)
        {

            Windows::Storage::StorageFolder^ _picturesLibrary = Windows::Storage::KnownFolders::PicturesLibrary;

            Concurrency::task<Windows::Storage::StorageFile^> _getFileObjectTask(_picturesLibrary->GetFileAsync(L"art.bmp"));

            auto _task2 = _getFileObjectTask.then([_completed, &i](Windows::Storage::StorageFile^ file)
            {

                i = 90210;

                _completed->set();

            });

        });

        auto asyncAction = ThreadPool::RunAsync(workItem);

        _completed->wait();


        int j = i;

    }

ところで、このメソッドは、ビジュアル スタジオのテストで終了後に、何らかの理由で例外が発生します。アプリでもテストしましたが、問題なく動作しました。テストの何が問題なのかよくわかりません。

C++/Wrl の例が欲しい人がいれば、私もそれを持っています。

2017 年 7 月 8 日更新: ここで要求されたのは、C++/Wrl の例です。Visual Studio 2017 のユニバーサル Windows (10) テスト プロジェクトでこれを実行しましCallback<Implements< RuntimeClassFlags<ClassicCom >, IWorkItemHandler , FtmBase >>Callback<IWorkItemHandler>。私が後者を持っていたとき、それが.exeプロジェクトにあったときを除いて、プログラムは詰まっていました. ここでこのソリューションを見つけました: https://social.msdn.microsoft.com/Forums/windowsapps/en-US/ef6f84f6-ad4d-44f0-a107-3922d56662e6/thread-pool-task-blocking-ui-thread。詳細については、「アジャイル オブジェクト」を参照してください。

#include "pch.h"
#include "CppUnitTest.h"
#include <Windows.Foundation.h>
#include <wrl\wrappers\corewrappers.h>
#include <wrl\client.h>
#include <wrl/event.h>
#include <memory>
#include "concrt.h"
#include <Windows.System.Threading.h>


using namespace Microsoft::VisualStudio::CppUnitTestFramework;
using namespace ABI::Windows::Foundation;
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
using namespace Windows::System::Threading;

using namespace ABI::Windows::Foundation;
using namespace ABI::Windows::System::Threading;



namespace TestWinRtAsync10
{
    TEST_CLASS(UnitTest1)
    {
    public:

        TEST_METHOD(AsyncOnThreadPoolUsingEvent10Wrl)
        {
            HRESULT hr = BasicThreadpoolTestWithAgileCallback();

            Assert::AreEqual(hr, S_OK);
        }

        HRESULT BasicThreadpoolTestWithAgileCallback()
        {

            std::shared_ptr<Concurrency::event> _completed = std::make_shared<Concurrency::event>();

            ComPtr<ABI::Windows::System::Threading::IThreadPoolStatics> _threadPool;
            HRESULT hr = GetActivationFactory(HStringReference(RuntimeClass_Windows_System_Threading_ThreadPool).Get(), &_threadPool);

            ComPtr<IAsyncAction> asyncAction;
            hr = _threadPool->RunAsync(Callback<Implements<RuntimeClassFlags<ClassicCom>, IWorkItemHandler, FtmBase>>([&_completed](IAsyncAction* asyncAction) -> HRESULT
            {

                // Prints a message in debug run of this test
                std::ostringstream ss;
                ss << "Threadpool work item running.\n";
                std::string _string = ss.str();
                std::wstring stemp = std::wstring(_string.begin(), _string.end());
                OutputDebugString(stemp.c_str());
                // 
                _completed->set();

                return S_OK;

            }).Get(), &asyncAction);

            _completed->wait();

            return S_OK;
        }

    };
}

2017 年 8 月 8 日更新: コメントごとのその他の例。

#include "pch.h"
#include "CppUnitTest.h"

#include <wrl\wrappers\corewrappers.h>
#include <wrl\client.h>
#include <wrl/event.h>
#include <memory>
#include "concrt.h"
#include <Windows.System.Threading.h>


#include <Windows.ApplicationModel.Core.h>

using namespace ABI::Windows::Foundation;
using namespace Microsoft::WRL;

namespace TestWinRtAsync10
{
    TEST_CLASS(TestWinRtAsync_WrlAsyncTesting)
    {

    public:

        TEST_METHOD(PackageClassTest)
        {
            ComPtr<ABI::Windows::ApplicationModel::IPackageStatics> _pPackageStatics;

            HRESULT hr = GetActivationFactory(Microsoft::WRL::Wrappers::HStringReference(RuntimeClass_Windows_ApplicationModel_Package).Get(), &_pPackageStatics);

            ComPtr<ABI::Windows::ApplicationModel::IPackage> _pIPackage;

            hr = _pPackageStatics->get_Current(&_pIPackage);

            ComPtr<ABI::Windows::ApplicationModel::IPackage3> _pIPackage3;

            hr = _pIPackage->QueryInterface(__uuidof(ABI::Windows::ApplicationModel::IPackage3), &_pIPackage3);

            ComPtr<__FIAsyncOperation_1___FIVectorView_1_Windows__CApplicationModel__CCore__CAppListEntry> _pAsyncOperation;

            hr = _pIPackage3->GetAppListEntriesAsync(&_pAsyncOperation);

            std::shared_ptr<Concurrency::event> _completed = std::make_shared<Concurrency::event>();

            _pAsyncOperation->put_Completed(Microsoft::WRL::Callback<Implements<RuntimeClassFlags<ClassicCom>, ABI::Windows::Foundation::IAsyncOperationCompletedHandler <__FIVectorView_1_Windows__CApplicationModel__CCore__CAppListEntry*>, FtmBase >>
                ([&_completed](ABI::Windows::Foundation::IAsyncOperation<__FIVectorView_1_Windows__CApplicationModel__CCore__CAppListEntry*>* pHandler, AsyncStatus status)
            {
                __FIVectorView_1_Windows__CApplicationModel__CCore__CAppListEntry* _pResults = nullptr;

                HRESULT hr = pHandler->GetResults(&_pResults);

                ComPtr<ABI::Windows::ApplicationModel::Core::IAppListEntry> _pIAppListEntry;

                unsigned int _actual;

                hr = _pResults->GetMany(0, 1, &_pIAppListEntry, &_actual);

                ComPtr<ABI::Windows::ApplicationModel::IAppDisplayInfo> _pDisplayInfo;

                hr = _pIAppListEntry->get_DisplayInfo(&_pDisplayInfo);

                Microsoft::WRL::Wrappers::HString _HStrDisplayName;

                hr =  _pDisplayInfo->get_DisplayName(_HStrDisplayName.GetAddressOf());


                const wchar_t * _pWchar_displayName = _HStrDisplayName.GetRawBuffer(&_actual);


                OutputDebugString(_pWchar_displayName);


                _completed->set();

                return hr;



            }).Get());

            _completed->wait();

        };

    };
}

これは次のように出力されました:

TestWinRtAsync10

于 2015-06-10T17:23:56.957 に答える