Skip to content

Question: Blocking behavior of buffer constructed from shared_ptr #297

@gmlueck

Description

@gmlueck

Our development team is fixing our implementation of buffer destructors to conform to the spec, so I'm trying to clarify exactly which cases require the destructor to block. I'd like to get confirmation from the committee on the behavior of a buffer that is constructed from a std::shared_ptr.

Section 4.7.2.3 "Buffer synchronization rules" does not list any special rules about the blocking behavior of a buffer that is constructed from a shared_ptr. Based on this, a reader would probably expect that the behavior is the same as a buffer that is constructed from a raw pointer -- which means the destructor always blocks.

However, section 4.7.4.3 "Shared SYCL ownership of the host memory" states:

When the buffer is destroyed and the data have potentially been updated, if the number of copies of the shared pointer outside the runtime is 0, there is no user-side shared pointer to read the data. Therefore the data is not copied out, and the buffer destructor does not need to wait for the data processes to be finished, as the outcome is not needed on the application’s side.

This clearly states that the buffer destructor has special blocking rules when it is constructed from a shared_ptr. I'd like to get confirmation that this is really our intention. If so, I'll submit a PR to move this description of the destructor to section 4.7.2.3, where we describe all the other cases of the buffer destructor blocking behavior.

If the wording in 4.7.4.3 is what we intend, then I think we expect the implementation to perform two checks of the shared_ptr in the destructor:

buffer::~buffer() {
  if (m_ptr.use_count() == 1) {
    /* block until commands using buffer complete */
    if (m_ptr.use_count() == 1) {
      /* copy data back to host if there are _still_ application references to it */
    }
  }
}

FWIW, shared_ptr::use_count is documented as unsafe in the usage I show above, so I think the check would really have to be like this instead:

buffer::~buffer() {
  std::weak_ptr tmp_ptr{m_ptr};
  m_ptr.reset();
  std::shared_ptr<T> tmp_ptr2 = tmp_ptr.lock();
  if (tmp_ptr2) {
     /* block until commands using buffer complete */
     /* ... */
  }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions