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

Shawn Waldon shawn.waldon at kitware.com
Tue Jul 5 17:57:50 EDT 2016


On Tue, Jul 5, 2016 at 5:45 PM, Elvis Stansvik <elvis.stansvik at orexplore.com
> wrote:

> 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?
>

The main thing to avoid is the reference count of the vtk object going to
0.  So I think the safest way to do this is to pass the vtkSmartPointer
around.  You could probably pass the raw pointer if you tweaked the
reference count manually, but the whole point of smart pointers is to avoid
having to do that.  I don't really see a reason to do a shallow copy.  If
the background thread was going to hang onto the object to do further
changes to it, you would want a deep copy since most vtk objects are not
threadsafe.  Keep in mind that if the filter that produced it is
re-executed then the data object will get overwritten (most filters reuse
output objects when re-executed).  But it sounds like you are letting the
pipeline that produced it be deleted while just keeping the object itself.


>
> 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?
>

The only thing I know of is that rendering and associated things (mappers,
actors, etc) have to be done in the foreground thread.  If others on the
list know about more, I would be glad to learn about them too.

HTH,
Shawn


> 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/d63f27d0/attachment.html>


More information about the vtkusers mailing list