[vtkusers] Returning filter output from thread using shallow copying vs smart pointer

Elvis Stansvik elvis.stansvik at orexplore.com
Tue Jul 5 17:11:23 EDT 2016


Just as I was going to ask a threading question on this list, someone else
did :) Oh well here's another one:

I'm rendering a compressed volume, and I've noticed that a big chunk of the
time-to-first-render for me is the initial reading of the volume. To keep
the UI responsive while the reading takes place, I decided to give
QtConcurrent::run + QFuture + QFutureWatcher a try as a mechanism to put
the reading in a different thread.

Here's a shortened version of what I did:

    auto future = QtConcurrent::run([&]() -> vtkImageData * {
        auto reader = vtkSmartPointer<HDF5ImageReader>::New();
        reader->setFileName("big_compressed_volume.hdf5");
        reader->Update();

        auto output = reader->GetOutput();
        auto result = output->NewInstance();
        result->ShallowCopy(output);

        return result;
    });

    auto futureWatcher = new QFutureWatcher<vtkImageData *>(this);

    connect(futureWatcher, &QFutureWatcher<vtkImageData *>::finished, [=]()
{
        auto imageData = futureWatcher->result();

        // ... Create the rendering part of the pipeline

        GetRenderWindow()->Render();
    });

    futureWatcher->setFuture(future);

This works great. Using QtConcurrent::run, I spin up a thread in which the
reading takes place. When the resulting vtkImageData is ready, I return a
shallow copy of it, which in turn causes the QFutureWatcher I set up to
emit the finished signal, upon which I construct the remaining (rendering)
part of the pipeline (which doesn't take much time compared to the reading,
about ~1/6 of the time).

Now to my questions:

1. Is this safe? Since the reader is destroyed by the time the rest of the
pipeline takes over (courtesy of using Qt signal delivery as a
synchronization point), there's no risk of concurrent access to VTK objects
here, right?

2. Can I always use this approach for segments of my pipeline up until the
rendering parts (up to the mapper?), or are there non-rendering parts of
VTK which simply cannot run in a separate thread?

3. Regarding the shallow copying, I first tried to return just

        return vtkSmartPointer<vtkImageData>(reader->GetOutput());

from the reader function. My thinking with this was that

   * I create a smart pointer, which should raise the ref count of the
object to 2, since the reader itself is still alive at that point and also
holds a reference,
   * a copy is then made of the smart pointer (for the return value of the
function), raising the refcount to 3,
   * when the function finally returns, the vtkSmartPointer I created, as
well as the vtkSmartPointer holding the reader goes out of scope and
destructs, which means the ref count goes down to 1.

But that's not what happens, I had a look at the ref count of the image
data I finally got in my slot (from futureWatcher->result()), and it was 2,
not 1 like I expected.

I'm obviously misunderstanding something here, anyone care to enlighten me?
Does the ref counting mechanism not work across thread boundaries?

Many thanks in advance,

Elvis
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://public.kitware.com/pipermail/vtkusers/attachments/20160705/12430d7e/attachment.html>


More information about the vtkusers mailing list