parallel_for_each上下文中的数组副本

Array copy in parallel_for_each context

本文关键字:数组 副本 上下文 for each parallel      更新时间:2023-10-16

我是AMP C++的新手。如果我在"parallel_for_each"函数中使用"memcpy",一切都会很好,但我知道这不是最佳做法。我尝试使用"copy_to",但它引发了一个异常。下面是一个简化的代码,重点是我遇到的问题。提前谢谢。

typedef std::vector<DWORD> CArrDwData;
class CdataMatrix
{
public:
    CdataMatrix(int nChCount) : m_ChCount(nChCount)
    {
    }
    void SetSize(UINT uSize)
    {
        // MUST be multiple of m_ChCount*DWORD
        ASSERT(uSize%sizeof(DWORD) == 0);
        m_PackedLength = uSize/sizeof(DWORD);
        m_arrChannels.resize(m_ChCount*m_PackedLength);
    }
    UINT GetChannelPackedLen() const
    {
        return m_PackedLength;
    }
    const LPBYTE GetChannelBuffer(UINT uChannel) const
    {
        CArrDwData::const_pointer cPtr = m_arrChannels.data() + m_PackedLength*uChannel;
        return (const LPBYTE)cPtr;
    }
public:
    CArrDwData m_arrChannels;
protected:
    UINT m_ChCount;
    UINT m_PackedLength;
};
void CtypDiskHeader::ParalelProcess()
{
    const int nJobs = 6;
    const int nChannelCount = 3;
    UINT uAmount = 250000;
    int vch;
    CArrDwData arrCompData;
    // Check buffers sizes
    ASSERT((~uAmount & 0x00000003) == 3);   // DWORD aligned
    const UINT uInDWSize = uAmount/sizeof(DWORD);   // in size give in DWORDs
    CdataMatrix arrChData(nJobs);
    arrCompData.resize(nJobs*uInDWSize);
    vector<int> a(nJobs);
    for(vch = 0; vch < nJobs; vch++)
        a[vch] = vch;
    arrChData.SetSize(uAmount+16); // note: 16 bytes or 4 DWORDs larger than uInDWSize
    accelerator_view acc_view = accelerator().default_view;
    Concurrency::extent<2> eIn(nJobs, uInDWSize);
    Concurrency::extent<2> eOut(nJobs, arrChData.GetChannelPackedLen());
    array_view<DWORD, 2> viewOut(eOut, arrChData.m_arrChannels);
    array_view<DWORD, 2> viewIn(eIn, arrCompData);
    concurrency::parallel_for_each(begin(a), end(a), [&](int vch)
    {
        vector<DWORD>::pointer ptr = (LPDWORD)viewIn(vch).data();
        LPDWORD bufCompIn = (LPDWORD)ptr;
        ptr = viewOut(vch).data();
        LPDWORD bufExpandedIn = (LPDWORD)ptr;
        if(ConditionNotOk())
        {
            // Copy raw data bufCompIn to bufExpandedIn
            // Works fine, but not the best way, I suppose:
            memcpy(bufExpandedIn, bufCompIn, uAmount);
            // Raises exception:
            //viewIn(vch).copy_to(viewOut(vch));
        }
        else
        {
            // Some data processing here
        }
    });
}
这是我的错。在原始代码中,viewOut(vch)的范围略大于viewIn(vch)的范围。使用这种方式,它会引发一个异常"runtime_exception"。在捕获它时,它会提供以下消息xcp.what()="由于扩展数据块不匹配而无法复制"。

我修复了用以下代码替换原始代码的代码:viewIn(vch).copy_to(viewOut(vch;它只复制源范围,这正是我所需要的。但仅编译而不编译受限AMP。

parallel_for_each无关,它看起来是array_view::copy_to的已知错误。请参阅以下帖子:

对并发的好奇::复制和array_view投影交互

您可以使用显式view_as()来修复此问题。我相信在您的情况下,您的代码应该是这样的。

viewIn(vch).copy_to(viewOut(vch));
// Becomes...
viewIn[vch].view_as<1>(concurrency::extent<1>(uInDWSize)).copy_to(viewOut(vch));

我无法编译您的示例,因此无法验证这一点,但我能够从类似的代码中获得一个异常,并使用view_as()进行修复。

如果要在C++AMP内核中复制数据,则需要将其作为一系列线程上的赋值操作来执行。以下代码将source的前500个元素复制到较小的dest阵列中。

array<int, 1> source(1000);
array<int, 1> dest(500);
parallel_for_each(source.extent, [=, &source, &dest](index<1> idx)
{
    if (dest.extent.contains(idx))
        dest[idx] = source[idx];
});