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

Elvis Stansvik elvis.stansvik at orexplore.com
Tue Jul 5 17:45:07 EDT 2016


2016-07-05 23:30 GMT+02:00 Shawn Waldon <shawn.waldon at kitware.com>:

> Hi Elvis,
>
> I've done something fairly similar in one of my applications, returning a
> vtkSmartPointer<vtkImageData> via a Qt signal/slot from a background
> thread.  And as far as I know the reference counting should work fine since
> the reference count is an atomic integer.  It has worked fine for me so far
> and VTK_DEBUG_LEAKS doesn't complain so the reference counts are working
> somehow.
>
> My guess about your reference count question:  You are returning the smart
> pointer by value.  The QFuture must be storing the smart pointer so that it
> can return it from the result() function.  And when you return it that way
> it creates a second smart pointer, which would increment the reference
> count to 2.
>

Ah, of course. Thanks! So then it's not a problem, my QFuture will be
destroyed shortly thereafter as well.

And thanks for also bringing up VTK_DEBUG_LEAKS, I didn't know about.

But, so I can assume that both approaches (raw pointer, return a shallow
copy) and returning a vtkSmartPointer are safe ways of doing this in this
case? Nothing in the VTK ref counting machinery that could go wrong?

Do you know if there are any things/gotchas or parts of VTK to watch out
for when putting parts of a pipeline in a separate thread like this?

Elvis


>
> HTH,
> Shawn
>
> On Tue, Jul 5, 2016 at 5:11 PM, Elvis Stansvik <
> elvis.stansvik at orexplore.com> wrote:
>
>> 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
>>
>> _______________________________________________
>> Powered by www.kitware.com
>>
>> Visit other Kitware open-source projects at
>> http://www.kitware.com/opensource/opensource.html
>>
>> Please keep messages on-topic and check the VTK FAQ at:
>> http://www.vtk.org/Wiki/VTK_FAQ
>>
>> Search the list archives at: http://markmail.org/search/?q=vtkusers
>>
>> Follow this link to subscribe/unsubscribe:
>> http://public.kitware.com/mailman/listinfo/vtkusers
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://public.kitware.com/pipermail/vtkusers/attachments/20160705/acc2b396/attachment.html>


More information about the vtkusers mailing list