[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