在Windows应用商店应用中,C ++(C#类似),做类似
的事情IAsyncAction^ Action = CurrentAppSimulator::ReloadSimulatorAsync(proxyFile);
create_task( Action ).then([this]()
{
}.wait();
导致未处理的异常。通常是
Microsoft C++ exception: Concurrency::invalid_operation at memory location 0x0531eb58
在尝试使用之前,我需要完成该操作以获取我的In App Purchase信息。 这里奇怪的是除了IAsyncAction之外的任何其他东西都等待。 IAsyncOperation和IAsyncOperationWithProgress工作正常,但是这个?异常然后崩溃。
老实说,我不知道IAsyncOperation和IAsyncAction之间有什么区别,它们看起来和我类似。
更新:
通过分析此页面http://msdn.microsoft.com/en-us/library/vstudio/hh750082.aspx,您可以发现IAsyncAction只是一个没有返回类型的IAsyncOperation。但是,您可以看到大多数IAsyncAction-s都是可以等待的。但真正的问题是某些Windows函数只是想在特定线程上执行(出于某种原因)。 ReloadSimulatorAsync就是一个很好的例子。
使用这样的代码:
void WaitForAsync( IAsyncAction ^A )
{
while(A->Status == AsyncStatus::Started)
{
std::chrono::milliseconds milis( 1 );
std::this_thread::sleep_for( milis );
}
AsyncStatus S = A->Status;
}
导致无限循环。如果调用其他功能,它实际上是有效的。这里的问题是,如果一切都是异步,为什么需要在特定线程上执行任务?它应该是RunOn(Main / UI)Thread或类似的。而不是Async。
已解决,请参阅答案;
答案 0 :(得分:5)
创建wait
后,concurrency::task
完全打败IAsyncAction^ Action = CurrentAppSimulator::ReloadSimulatorAsync(proxyFile);
create_task( Action ).then([this]()
{
}).wait();
// do important things once the simulator has reloaded
important_things();
会使得任务失败。
您必须意识到,在Windows运行时,有许多异步操作无法(或不应该)在UI线程上运行(或等待);你找到了其中一个,现在你正试图等待它。您可能会遇到异常,而不是可能导致死锁。
要解决此问题,您需要使用a continuation。你大部分都在那里;你已经定义了一个延续函数:
then
...但你没有使用它。传递到IAsyncAction^ Action = CurrentAppSimulator::ReloadSimulatorAsync(proxyFile);
create_task( Action ).then([this]()
{
// do important things once the simulator has reloaded
important_things();
});
的函数的目的是在任务完成后将其称为关闭UI线程。所以,相反,你应该这样做:
{{1}}
重要的重新加载代码在任务完成之前不会运行,它将在后台线程上运行,因此它不会阻止或死锁UI。
答案 1 :(得分:5)
这是完成工作的神奇修复:
void WaitForAsync( IAsyncAction ^A )
{
while(A->Status == Windows::Foundation::AsyncStatus::Started)
{
CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent);
}
Windows::Foundation::AsyncStatus S = A->Status;
}
答案 2 :(得分: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;
}
顺便说一下,由于某些原因,这个方法在visual studio测试结束后会导致异常。我也在应用程序中对它进行了测试,但它没有问题。我不太确定测试的问题是什么。
如果有人想要一个C ++ / Wrl示例,那么我也有。
更新07/08/2017 :这里要求的是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。请参阅&#34;敏捷对象&#34;欲获得更多信息。
#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;
}
};
}
更新08/08/2017:更多示例,根据评论。
#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
答案 3 :(得分:0)
以防万一,这里有人需要C ++ / WinRT中的解决方案。假设您有返回ProcessFeedAsync()
的函数IAsyncAction
,只需执行以下简单代码即可:
winrt::init_apartment();
auto processOp{ ProcessFeedAsync() };
// do other work while the feed is being printed.
processOp.get(); // no more work to do; call get() so that we see the printout before the application exits.