连续链中是否需要共享指针?

时间:2015-01-30 22:30:01

标签: visual-c++ concurrency task c++-cx ppl

我有一个使用lambda表达式的连续链,其中一个任务分配给一个变量,下一个任务从该变量读取。 Microsoft suggests using a shared_ptr to wrap the variable even when the variable is a reference-counted handle (^).当由lambda表达式按值捕获时,引用计数句柄是否会增加其引用计数?那么为什么有必要用[{1}}包装引用计数句柄?

1 个答案:

答案 0 :(得分:3)

文档清楚表明他们关注的案例是

  

连续链中的一个任务分配给变量,另一个任务读取该变量

(重点是我的。)这不是对象生命周期的问题,而是对象身份的问题。

Hilo project获取此示例,密切关注decoder变量(shared_ptr<BitmapDecoder^>):

task<InMemoryRandomAccessStream^> ThumbnailGenerator::CreateThumbnailFromPictureFileAsync(
    StorageFile^ sourceFile, 
    unsigned int thumbSize)
{
    (void)thumbSize; // Unused parameter
    auto decoder = make_shared<BitmapDecoder^>(nullptr);
    auto pixelProvider = make_shared<PixelDataProvider^>(nullptr);
    auto resizedImageStream = ref new InMemoryRandomAccessStream();
    auto createThumbnail = create_task(
        sourceFile->GetThumbnailAsync(
        ThumbnailMode::PicturesView, 
        ThumbnailSize));

    return createThumbnail.then([](StorageItemThumbnail^ thumbnail)
    {
        IRandomAccessStream^ imageFileStream = 
            static_cast<IRandomAccessStream^>(thumbnail);

        return BitmapDecoder::CreateAsync(imageFileStream);

    }).then([decoder](BitmapDecoder^ createdDecoder)
    {
        (*decoder) = createdDecoder;
        return createdDecoder->GetPixelDataAsync( 
            BitmapPixelFormat::Rgba8,
            BitmapAlphaMode::Straight,
            ref new BitmapTransform(),
            ExifOrientationMode::IgnoreExifOrientation,
            ColorManagementMode::ColorManageToSRgb);

    }).then([pixelProvider, resizedImageStream](PixelDataProvider^ provider)
    {
        (*pixelProvider) = provider;
        return BitmapEncoder::CreateAsync(
            BitmapEncoder::JpegEncoderId, 
            resizedImageStream);

    }).then([pixelProvider, decoder](BitmapEncoder^ createdEncoder)
    {
        createdEncoder->SetPixelData(BitmapPixelFormat::Rgba8,
            BitmapAlphaMode::Straight,
            (*decoder)->PixelWidth,
            (*decoder)->PixelHeight,
            (*decoder)->DpiX,
            (*decoder)->DpiY,
            (*pixelProvider)->DetachPixelData());
        return createdEncoder->FlushAsync();

    }).then([resizedImageStream]
    {
        resizedImageStream->Seek(0);
        return resizedImageStream;
    });
}

decoder变量首先在continuation之外定义,因为在多个continuation中需要它。此时,其值为null。它是在第二个延续中获得并设置的,该对象的属性(PixelWidth等)在第四个延续中使用。

您是要将decoder定义为BitmapDecoder^,将其设置为nullptr,然后在第二个续集中为其指定一个值,该更改不会传播到后续延续因为更改无法反映回初始句柄(lambda已经创建了句柄的副本,实质上是复制了内存地址0x00000000)。

为了更新原始版本(以及后续引用),您需要一个额外的间接(例如BitmapDecoder^*)。 shared_ptr<BitmapDecoder^>是一个这样的间接,并且是一个有用的,因为您不需要管理指针的生命周期,这与原始指针不同,这就是为什么在文档中建议它。

在其他情况下,捕获Object^就足够了,例如,如果我在我的延续之外创建了一个TextBlock^并在第一个延续中设置了它的一些属性并且读取了其他一些属性随后的延续。在这种情况下,所有句柄都引用相同的底层对象,并且没有延续尝试覆盖对象本身的标识。 (但是,如最初提到的,这不是文档所指的用例。)