为什么不执行CreateFileAsync()延续?

时间:2016-11-21 18:18:09

标签: windows-runtime c++-cx

在下面的代码中,CreateFileAsync()的延续既不打印也不访问pdone。但是,会创建零长度文件Hello.txt。

auto pdone = make_shared<bool>(false);

create_task(folderLocal->CreateFileAsync("Hello.txt", CreationCollisionOption::ReplaceExisting)).then([pdone](StorageFile ^file) {
    OutputDebugString(L"In CreateFileAsync continuation!\n");
    *pdone = true;
});

create_task([pdone]{
    OutputDebugString(L"In my task!\n");
});

create_async([pdone]{
    OutputDebugString(L"In my async!\n");
});

while (!*pdone) {}
OutputDebugString(L"Done!\n");

在调试器中:

In my task!
In my async!

我对调试WinRT线程还不是很熟悉,但我没有看到任何明显的异常或任何原因不能执行异步操作的继续。目标平台是Hololens模拟器。

任何想法都表示赞赏。 谢谢!

2 个答案:

答案 0 :(得分:1)

上面的Harry评论很可能是罪魁祸首 - 如果你在UI线程上发起这个,那么默认情况下,C ++任务库(PPL)将尝试在同一个线程上安排完成。如果您正在旋转等待完成的线程(经典死锁),这将永远不会发生。

如果你必须这样做(虽然你真的应该试着避免它),你需要使用&#34;继续上下文&#34;告诉PPL在其他地方运行延续。

这是一个例子。首先,基本的XAML(只是粘贴在空白C ++ XAML项目的Grid内):

<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
    <Button Content="Hang the UI thread" Click="Hang"/>
    <Button Content="Do not do this" Click="DoNotDoThis"/>
</StackPanel>

代码(只需在MainPage构造函数后粘贴):

using namespace Windows::Storage;
using namespace concurrency;

void DoIt(task_continuation_context& context)
{
  auto folder = ApplicationData::Current->LocalFolder;
  auto done = std::make_shared<bool>(false);
  create_task(folder->CreateFileAsync(L"x", CreationCollisionOption::ReplaceExisting))
  .then([done](StorageFile^ file) mutable
  {
    OutputDebugString(L"Done creating file\n");
    *done = true;
  }, context);

  OutputDebugString(L"Going to wait... DO NOT DO THIS IN PRODUCTION CODE!\n");
  while (!*done)
    ;

  OutputDebugString(L"Done waiting\n");
}

void MainPage::Hang(Platform::Object^ sender, RoutedEventArgs^ e)
{
  OutputDebugString(L"Starting Hang\n");
  // The default context == the UI thread (if called from UI)
  DoIt(task_continuation_context::use_default());
  OutputDebugString(L"Ending Hang\n");
}

void MainPage::DoNotDoThis(Platform::Object^ sender, RoutedEventArgs^ e)
{
  OutputDebugString(L"Starting DoNotDoThis\n");
  // An arbitrary context will pick another thread (not the UI)
  DoIt(task_continuation_context::use_arbitrary());
  OutputDebugString(L"Ending DoNotDoThis\n");
}

如上所述,你不应该这样做。如果您需要同步文件I / O,并且您正在访问自己包中的文件,请使用Win32 API CreateFile2。如果您需要访问包之外的文件(例如,从文件选择器或照片库),您应该使用完全异步编程方法。

答案 1 :(得分:0)

我相信使用task_continuation_context :: use_arbitarty()是这样做的正确方法,但我认为微软建议使用它略有不同,除非我误解了这个链接(一直滚动到底部):https://msdn.microsoft.com/en-us/library/hh750082.aspx

create_task(folderLocal->CreateFileAsync("Hello.txt", CreationCollisionOption::ReplaceExisting)).then([pdone](StorageFile ^file) {
    OutputDebugString(L"In CreateFileAsync continuation!\n");
    *pdone = true;
}, task_continuation_context::use_arbitrary());