Windows 10 UWP 17 of N: Build 2016 C++ Asynchronous in UWP

  • 233
  • 0
  • UAP
  • 2018-01-21

介紹在Visual Studio 2015 Update 2使用C++\CX的新特性。

在C# 5.0的時候帶來了Async Await的非同步開發模式,這是針對API如果會超過約10ms的API進行非同步的處理方式。

而在C#的Async Await的使用方式大致如下

public async Task HttpDownloadAsync(Uri uri)
        {
            try
            {
                using (var client = new HttpClient())
                using (var response = await client.GetAsync(uri))
                {
                    response.EnsureSuccessStatusCode();
                    var responseStr = await response.Content.ReadAsStringAsync();
                    System.Diagnostics.Debug.WriteLine(responseStr);
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex.Message);
            }
        }

這樣就是使用HttpClient抓取Http的資料,但是在C++還是沒有像C#這麼方便可以直接使用Async Await的語法來建立非同步的API Callback。

以下程式碼使用C++\Cx的語法來建立非同步的CallBack。

void CppApp1::MainPage::DoThingPPLAsync()
{
	auto picker = ref new FileOpenPicker();
	picker->FileTypeFilter->Append(L".png");
	picker->FileTypeFilter->Append(L".jpg");
	picker->FileTypeFilter->Append(L".jpeg");
	picker->FileTypeFilter->Append(L".gif");
	picker->ViewMode = PickerViewMode::Thumbnail;
	picker->SuggestedStartLocation = PickerLocationId::Desktop;
	create_task(picker->PickSingleFileAsync()).then([this](Windows::Storage::StorageFile^ file)
	{
		create_task(file->OpenReadAsync()).then([this](Windows::Storage::Streams::IRandomAccessStreamWithContentType^ fileStream)
		{
			auto bImg = ref new BitmapImage();
			create_task(bImg->SetSourceAsync(fileStream)).then([this, bImg](void)
			{
				this->ProfileImage->Source = bImg;
			});
		});
	});
}

這邊要說明到create_task是在C++\Cx的建立Task的方式,但是這樣的寫法就是變成如上地巣狀Callback,降低了可讀性以及語法上的直觀。使用create_task需要再header檔案include ppltask如下所示

#include <ppltasks.h>

並且加上concurrency的namespace

using namespace concurrency;

以上是基礎的使用非同步的c++\cx語法。


接者在來說使用pplawait的非同步的方式,如下所示需要include pplawait的header並且調整Project 的屬性,並在Platform toolset的調整成Visual C++ Compiler Nov 2013 CTP (CTP_Nov2013)

#include <pplawait.h>

void CppApp1::MainPage::DoThingAsync2()
{
	auto picker = ref new FileOpenPicker();
	picker->FileTypeFilter->Append(L".png");
	picker->FileTypeFilter->Append(L".jpg");
	picker->FileTypeFilter->Append(L".jpeg");
	picker->FileTypeFilter->Append(L".gif");
	picker->ViewMode = PickerViewMode::Thumbnail;
	picker->SuggestedStartLocation = PickerLocationId::Desktop;
	auto file = __await picker->PickSingleFileAsync();
	auto fileStream = __await file->OpenReadAsync();
	auto bImg = ref new BitmapImage();
	__await bImg->SetSourceAsync(fileStream);
	this->ProfileImage->Source = bImg;
}

那麼接者來介紹VS 2015 Update 2所加入的新功能,先是在header的部分宣告非同步的method

concurrency::task<void> DoThingAsync();

接者在CPP檔案實作該非同步方法

#include <experimental\resumable>

task<void> CppApp1::MainPage::DoThingAsync()
{
	auto picker = ref new FileOpenPicker();
	picker->FileTypeFilter->Append(L".png");
	picker->FileTypeFilter->Append(L".jpg");
	picker->FileTypeFilter->Append(L".jpeg");
	picker->FileTypeFilter->Append(L".gif");
	picker->ViewMode = PickerViewMode::Thumbnail;
	picker->SuggestedStartLocation = PickerLocationId::Desktop;
	auto file = co_await picker->PickSingleFileAsync();
	auto fileStream = co_await file->OpenReadAsync();
	auto bImg = ref new BitmapImage();
	co_await bImg->SetSourceAsync(fileStream);
	this->ProfileImage->Source = bImg;
}

這邊include的是從C++ 11的非同步語法延伸過來的非同步概念!語法上使用的co_await和C#的Async await非常相近,這樣的寫法提高了C++的可讀性。這樣在C++\CX上撰寫非同步的Code就比較容易上手拉~基本上在UWP調用Perofmance focus的API時撰寫C++\Cx的效能會獲得大量提升(當然也是要撰寫的正確運算邏輯才會有效果)。

最後這邊補充一下不論是使用 create_task 或是 __await 或是 co_await 的非同步語法都和C#的Async await不同!在C#的部分是在Compile層級做非常複雜的運算處理,C#的Complier幫我們實作了State machine的機制來達到非同步的效果。
最後需要再Project的Properties的選單內的C++下的Command Line中加入 /await才不會出現錯誤喔!

 

***以上Code以及說明都有可能隨著Windows 10 的版本以及Visual Studio 2015版本有所調整!***

參考資料 Asynchronous programming with C++ UWP

下次再分享Windows 10 的新技術拉~