concurrency::array_view – data source lifetime
The previous posts in this series on C++ AMP array_view covered:
- Introduction to array_view and some of its key semantic aspects
- Implicit synchronization on destruction of array_views
- array_view discard_data function
- Caching and coherence policies underlying array_view implementation
- Using a staging array as an array_view’s data source
This post will talk about the lifetime management of an array_view’s data source.
array_view data source lifetime
An array_view is bound to a data source and the data source’s memory allocation must outlive the array_view. Any attempts to access an array_view after the data source memory has been de-allocated will result in undefined behavior. Remember to account for the implicit synchronization on destruction of the last array_view of a data source.
Guideline A: Ensure that the memory allocation corresponding to a data source outlives all array_views referencing that data source.
array_view<float> GenerateRandomNumbers(float *seeds, int count)
{
array_view<const float> seedView(count, seeds);
std::vector<float> outRandVec(count);
array_view<float> outRandView(outRandVec.size(), outRandVec);
outRandView.discard_data();
parallel_for_each(outRandView.extent, [seedView, outRandView](index<1> idx) restrict(amp) {
...
});
// Guideline A violation: Returning an array_view that uses a local std::vector as its data
// source which will be destructed at the end of this function. Accessing the array_view after the
// std::vector data source is destructed has undefined behavior.
return outRandView;
}
An exception in this regard is the use of a concurrency::array container as the data source of an array_view. The memory allocation underlying a concurrency::array is reference counted and lives as long as there is a live array or array_view reference to it. Hence if you are using a concurrency::array as a data source for an array_view, you need not worry about having to keep the source array object live – it is fine for any array_views created from an array to outlive the array itself. In fact, this is a useful technique if an array_view needs to be encapsulated within another user-defined type. In such a scenario, it is often desirable that the type encapsulating the array_view also encapsulates the data source of the array_view so that their lifetimes are managed together. However, if an object of this user-defined type has to be captured in a parallel_for_each kernel, the data source itself cannot be a data member of this user-defined type (since a concurrency::array, a CPU pointer or an STL container cannot be captured by value in a parallel_for_each kernel per the restrict(amp) restrictions). Creating an array_view over a temporary array solves this problem – the buffer allocation underlying the array/array_view being reference counted, lives even after the temporary array is destructed until the array_view itself is destructed.
template <typename value_type>
class Matrix
{
public:
// The Matrix type's array_view data member can be constructed from
// a temporary array without the array itself being a data member of the type
// Memory underlying the array is freed when the array_view member is
// destructed in the Matrix destructor
Matrix(int height, int width)
: _M_data_view(array<value_type, 2>(height, width))
{
}
array_view<value_type> GetRow(int rowNumber) restrict(cpu, amp)
{
return _M_data_view[rowNumber];
}
value_type& operator(int i, int j) restrict(cpu, amp)
{
return _M_data_view(i, j);
}
private:
array_view<value_type, 2> _M_data_view;
};
Matrix<float> mA(M, W);
// The Matrix object can be captured in the parallel_for_each by value
// as it only contains an array_view data member. If the type has a concurrency::array
// data member, it would have been illegal to capture a Matrix object by value
// in the parallel_for_each kernel
parallel_for_each(mA.extent, [=](index<2> idx) restrict(amp) {
mA(idx) = fast_math::sqrt(mA(idx));
});
In closing
In this post we looked at the importance of ensuring the right lifetime for an array_view’s data source.
If there are other array_view topics that are not covered on our blog, please let me know so I can address them too. I would love to hear your feedback, comments and questions below or in our MSDN forum.
Comments
- Anonymous
May 22, 2013
The comment has been removed