Exception “从不执行并发任务”;然后();nor引发异常(C+;+;/CX UWP)
使用Concurrency::task从代码中列出一些设备时出现问题: 去年在visual studio 2015中使用此代码的用法:Exception “从不执行并发任务”;然后();nor引发异常(C+;+;/CX UWP),exception,concurrency,uwp,task,c++-cx,Exception,Concurrency,Uwp,Task,C++ Cx,使用Concurrency::task从代码中列出一些设备时出现问题: 去年在visual studio 2015中使用此代码的用法: Concurrency::create_task(Windows::Devices::Enumeration::DeviceInformation::FindAllAsync(Windows::Devices::Midi::MidiInPort::GetDeviceSelector())) .then([](Windows::Devices::Enume
Concurrency::create_task(Windows::Devices::Enumeration::DeviceInformation::FindAllAsync(Windows::Devices::Midi::MidiInPort::GetDeviceSelector()))
.then([](Windows::Devices::Enumeration::DeviceInformationCollection ^midiDeviceCollection) {
for (Windows::Devices::Enumeration::DeviceInformation^ portInformation : midiDeviceCollection){
//do stuff with device
}
});
但几个月后。。。今天,我必须更新我的应用程序(同时切换到VS2017)。所以我重新打开并更新了项目,遗憾的是,这段代码不再按它应该的方式工作。“then()”部分中设置的断点永远不会到达,代码将继续执行,不会出错,就好像从未调用过我的任务一样
我想知道在执行DeviceInformation::FindAllAsync时是否有错误,该错误不允许“then()”部分运行。在对任务()进行了一些研究之后,我找到了一种在任务运行时捕获异常的方法,因此我将代码转换为:
IAsyncOperation<DeviceInformationCollection^>^ deviceOp = DeviceInformation::FindAllAsync(MidiInPort::GetDeviceSelector());
Concurrency::task<DeviceInformationCollection^> deviceEnumTask = Concurrency::create_task(deviceOp);
deviceEnumTask.then([](Concurrency::task<DeviceInformationCollection^> t){
try{
DeviceInformationCollection ^midiDeviceCollection = t.get();
for (DeviceInformation^ portInformation : midiDeviceCollection) {
//do stuff with device
}
}catch (Platform::Exception^ e){
//do stuff with device
OutputDebugString(e->Message->Data());
}
});
IAsyncOperation^deviceOp=DeviceInformation::findalsync(midinport::GetDeviceSelector());
并发::任务设备枚举任务=并发::创建任务(deviceOp);
deviceEnumTask.then([](并发::任务t){
试一试{
DeviceInformation集合^midiDeviceCollection=t.get();
for(设备信息^portInformation:midiDeviceCollection){
//用这个设备做事
}
}捕获(平台::异常^e){
//用这个设备做事
OutputDebugString(e->Message->Data());
}
});
同样的结果是,应用程序从不进入“then()”,也不会引发异常:-(
所以我的问题是:这里的问题是什么?这段代码是列出设备的最常见的方式,我在网络上的其他地方都看到过它(而且它去年在我的案例中起了作用),所以我应该在其他地方犯了错误或遗漏了一些东西
这是捕获任务中错误的好方法吗
更多信息:此代码直接在主页构造函数中调用,就在InitializeComponent()之后。我正在运行VS2017,目标平台最小版本为10.0.10240.0,目标平台版本为10.0.15063.0。该应用程序是在桌面x64机器上构建和测试的
非常感谢你的帮助
编辑:
感谢吴荪婷和大卫·普里查德(见下文)我已经能够找出问题的根源。正如答案中所述,上面的代码实际上是有效的,并且在按照David的建议调整错误处理后非常清晰和完整。在我的测试中,我的断点也放在了正确的位置。但事实上,在没有意识到这一点的情况下,我在测试中使用了一些更深层次的阻塞代码“//使用设备执行任务”(此处不可见)。这会阻塞主页构造函数,使其无法继续执行,直到调用的任务完成……显然,只要主页构造未结束,任务仍与主线程执行相链接,并且不会运行,在我的情况下,从未发生过这种情况->死锁
同样的结果是,应用程序从不进入“then()”,也不会引发异常
通过在我这边的测试,当在task::then
内部设置断点时,其委托可以成功执行,如下所示:
应用程序确实输入了委托。如果您仅在任务::然后
代码行设置断点并使用F10
跳过,它将跳过委托,因为任务::然后
方法立即返回,并且其委托在异步工作成功完成之前不会运行。详细信息请参考
这是捕获任务中错误的好方法吗
根据,您试图捕获错误的方式似乎是正确的。如果异步操作导致引发异常,则继续将永远不会执行。您将获得通过task::get
传输到任务的任何异常
您还可以检查“不再工作”是否是由于没有
midinport
造成的。请尝试获取上图所示的设备大小。我无法回答您问题的MIDI部分。我可以回答异常处理代码
首先-我怀疑您是否在findalsync
中看到异常,因为未观察到的异常通常会导致应用程序崩溃(或中断到调试器)
第二,上面的异常处理程序似乎混淆了两种类型的延续:
- 类型1:常规继续,在异步方法返回其结果后继续工作
e、 例如,
deviceEnumTask.then([](DeviceInformation Collection^){…})
- 类型2:异常处理延续,用于处理任务链中的任何异常
e、 例如,
deviceEnumTask.then([](并发::任务t){…})
using namespace Windows::Devices::Enumeration;
using namespace Windows::Devices::Midi;
Concurrency::create_task(
DeviceInformation::FindAllAsync(MidiInPort::GetDeviceSelector())
).then([](DeviceInformationCollection ^midiDeviceCollection) {
for (DeviceInformation^ portInformation : midiDeviceCollection){
//do stuff with device
}
}).then([] Concurrency::task<void> t) {
try {
t.get();
OutputDebugString(L"No exceptions seen");
}
catch (Platform::Exception ^e) {
OutputDebugString(e->Message->Data());
}
});
使用命名空间Windows::Devices::Enumeration;
使用名称空间Windows::Devices::Midi;
并发::创建任务(
DeviceInformation::FindAllAsync(MIDINPort::GetDeviceSelector())
)。然后([](设备信息集合^midiDeviceCollection){
for(设备信息^portInformation:midiDeviceCollection){
//用这个设备做事
}
}).然后([]并发::任务t){
试一试{
t、 get();
OutputDebugString(L“未发现异常”);
}
捕获(平台::异常^e){
OutputDebugString(e->Message->Data());
}
});
关于错误处理的解释非常清楚,这是我错过的。