1

私は、C++ 環境内で PPL タスクを使用することに関してはまったくの初心者なので、次の C# コードの C++ 構文が何であるかを理解するのに苦労しています。

private static async Task<RandomAccessStreamReference> GetImageStreamRef()
{
    return RandomAccessStreamReference.CreateFromStream(await GetImageStream());
}

private static async Task<IRandomAccessStream> GetImageStream()
{
    var stream = new InMemoryRandomAccessStream();
    var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.BmpEncoderId, stream);
    encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore, width, height, 96, 96, imageBytes);
    await encoder.FlushAsync();
    return stream;
}

この C# コードは、Windows Store reversi Microsoft sample codeから取得したものです。私がこれまでに得た最高のものはこれです:

Concurrency::task<IRandomAccessStream^> GetImageStream()
{
    auto stream = ref new InMemoryRandomAccessStream();
    task<BitmapEncoder^>(BitmapEncoder::CreateAsync(BitmapEncoder::JpegEncoderId, Stream)).then([this, stream, width, height, imageBytes](BitmapEncoder^ encoder)
    {
        encoder->SetPixelData(BitmapPixelFormat::Rgba8, BitmapAlphaMode::Ignore, width, height, 96.0, 96.0, imageBytes);
        return encoder->FlushAsync();
    }).then([this, stream]()
    {
        return stream; //Does this even make sense?
    });
    //return stream; //Not sure if I should have this here?
}

ただし、次のコンパイル エラーが発生します。

error C4716: 'GetImageStream' : must return a value

このエラーが発生する理由は理解できますが、2 つの異なる場所で戻り値を持たずにタスクを返す関数を作成する方法がわかりません。GetImageStream にもまだ取り組んでいません。

私はこれに正しい道を歩んだかどうかさえ確信が持てません...

ありがとうございました!

4

2 に答える 2

3

あなたは本当に近いです。見逃しているかもしれない重要なポイントは、新しいタスクthenが返されることです。したがって、チェーンの最後がタスクのタイプを決定します。then

auto t = task<int>([] { return 0; });
// t is task<int>

auto t = task<int>([] { return 0; })
.then([](int i) { return 3.14; });
// t is task<double>

auto t = task<int>([] { return 0; })
.then([](int i) { return 3.14; })
.then([](double d) { return "foo"; });
// t is task<const char*>

最初の行だけをちらりと見ると、常に を持っているように見えますが、task<int>すぐに呼び出すと必ずしもそうではないことがわかりますthen

task次に、関数がストリーム自体ではなくを返すことに注意してください。通常、チェーンの最後thenに、関数から返すタスクを返します。タスクをローカル変数に格納するのではなく、単に返すだけです。例えば:

task<const char*>
get_foo()
{
    return task<int>([] { return 0; })
    .then([](int i) { return 3.14; })
    .then([](double d) { return "foo"; });
}

繰り返しますが、ちょっと奇妙に見えますtask<int>。これはcreate_task、タスク コンストラクターを明示的に呼び出すのではなく、を使用することで適切に処理されます。これにより、タスクのタイプを明示的に指定する必要がまったくなくなります。さらに、代わりに派生物create_asyncを返したい場合は、簡単に変更できます。IAsyncInfo

私は にまったく慣れてBitmapEncoderいませんが、トリックを行う可能性のあるコードの微調整バージョンを次に示します。

Concurrency::task<IRandomAccessStream^> GetImageStream()
{
    auto stream = ref new InMemoryRandomAccessStream();
    return create_task(BitmapEncoder::CreateAsync(BitmapEncoder::JpegEncoderId, stream))
    .then([this, width, height, imageBytes](BitmapEncoder^ encoder)
    {
        // are width, height, and imageBytes member variables?
        // if so, you should only need to capture them OR "this", not both
        encoder->SetPixelData(BitmapPixelFormat::Rgba8, BitmapAlphaMode::Ignore, width, height, 96.0, 96.0, imageBytes);
        return encoder->FlushAsync();
    }).then([stream]()
    {
        // this should work fine since "stream" is a ref-counted variable
        // this lambda will keep a reference alive until it uses it
        return stream;
    });
}

唯一の実際の変更はcreate_task、その結果を使用してすぐに返すことです。

私はまだ PPL を自分自身で学んでいますが、これまでに学んだことの 1 つは、作成したタスクに対して常に何かを実行する必要があるということです。通常行うことは、 を使用thenしてそれを新しい/別のタスクに変えることですが、最後の によって返されたタスクで何かを行う必要がありますthen。多くの場合、上記のように単に返却します。when_allまたはでグループ化されるタスクのコンテナーに追加することがありますwhen_anyget()場合によっては、結果を待つために自分で呼び出すこともあります。しかし重要なのは、タスクを作成してそれに対して何もしない場合、おそらく何か問題があるということです。

于 2013-05-26T13:27:24.030 に答える
0

また、誰かが気になる場合は、上記の GetImageStreamRef を C++ バージョンで実装する方法を次に示します。

task<RandomAccessStreamReference^> GetImageStreamRef()
{
    return GetImageStream().then([](IRandomAccessStream^ pStream)
    {
        return RandomAccessStreamReference::CreateFromStream(pStream);
    });
}

また、これらのタスクで .get() を使用しないでください。そうしないと、「Windows ランタイム STA でタスクを待機するのは違法です」という例外がスローされます。このイメージ ストリーム参照の値を取得する適切な方法は、たとえば、DataRequest でビットマップ データを設定する DataRequestHandler を使用することです。

void OnBitmapRequested(DataProviderRequest^ request)
{
    auto Deferral = request->GetDeferral();
    GetImageStreamRef().then([Deferral, request](RandomAccessStreamReference^ pStreamRef)
    {
        try
        {
            request->SetData(pStreamRef);
            Deferral->Complete();
        }
        catch( std::exception ex )
        {
            Deferral->Complete();
            throw ex;   //Propagate the exception up again
        }
    });
}
于 2013-05-29T20:06:25.933 に答える