[swift-users] Postponing owned object deinitialization
Nate Chandler
nathaniel.chandler at gmail.com
Mon Feb 27 12:34:55 CST 2017
Hi Ole,
A quick follow-up--are you suggesting calling withExtendedLifetime inside
the closure passed to async, as below?
class AsyncHandle {
let handle: Handle
deinit {
let handle: Handle = self.handle
q.async {
withExtendedLifetime(handle) {}
}
}
}
If so, it seems that that may be a final answer to (3). It does raise an
additional question, however:
(6) Would we expect calling withExtendedLifetime to have different behavior
from calling an @inline(never) function from a closure enqueued async from
deinit?
Thank you again,
Nate Chandler
On Mon, Feb 27, 2017 at 1:20 PM Nate Chandler <nathaniel.chandler at gmail.com>
wrote:
> Hi Ole,
>
> Thank you very much for your response.
>
> I don't believe withExtendedLifetime can help out here. The trouble is
> that withExtendedLifetime only extends a lifetime until the end of a scope,
> synchronously.
>
> In my case, I want to extend the lifetime of Handle from AsyncHandle's
> deinit until a closure enqueued asynchronously (from AsyncHandle's deinit)
> is invoked. Using withExtendedLifetime, I could only extend the lifetime
> of Handle until the end of AsyncHandle's deinit method.
>
> I want to write
>
> class AsyncHandle {
>
> let handle: Handle
>
> deinit {
> let handle: Handle = self.handle
> q.async {
> letHandleDieNow(handle)
> }
> }
>
> }
>
> If I tried to use withExtendedLifetime, I could only write
>
> class AsyncHandle {
>
> let handle: Handle
>
> deinit {
> let handle: Handle = self.handle
> withExtendedLifetime(handle) { handle in
> q.async {
> // This is where I want handle to finally be deinitialized
> }
> }
> // This is where handle is actually deinitialized, prior
> (probably) to the invocation of the closure passed to async
> }
>
> }
>
> Please let me know if I am misunderstanding your suggestion or the
> withExtendedLifetime API.
>
> Thank you very much,
> Nate Chandler
>
>
> On Mon, Feb 27, 2017 at 12:31 PM Ole Begemann <ole at oleb.net> wrote:
>
> On 27/02/2017 15:17, Nate Chandler via swift-users wrote:
> > Hello all,
> >
> > I'm encountering a behavior around object lifetime and deinitialization
> > that is surprising to me. Here's an approximation of what I'm
> encountering:
> >
> > I have a class Handle whose deinit must execute on a certain queue
> > (let's call it q--in my case it is a global queue). I have a second
> > class AsyncHandle which owns a Handle and needs to be able to deinit on
> > any queue. There's a tension to resolve between the deinitialization
> > contracts of Handle and AsyncHandle. To resolve it, in AsyncHandle's
> > deinit, I am binding the owned instance of Handle to a local variable,
> > dispatching async onto the q, and from the async closure, calling
> > extendLifetime with the Handle, where extendLifetime is the following:
> >
> > @inline(never) func extendLifetime<T : AnyObject>() {}
> >
> > AsyncHandle's deinit looks like
> >
> > deinit {
> > let handle = self.handle
> > q.async {
> > extendLifetime(handle)
> > }
> > }
> >
> > This approach seems to work--the Handle gets deinit on q, the
> > appropriate queue. Most of the time. In the debugger, there is never a
> > problem. Occasionally and inconsistently, on some devices, I am,
> > however, seeing a behavior that _seems_ to be the synchronous
> > deallocation of Handle from AsyncHandle's deinit on the queue that
> > AsyncHandle happens to be deinitializing on (not q). If that is indeed,
> > the behavior I'm seeing, I do not understand why it is happening.
> >
> > A few questions:
> > (1) Given an object B owned (exclusively--no other objects have
> > references to A) by an object A, is it legal to extend the lifetime of B
> > in the deinit of A? (It might conceivably not be legal if there is a
> > rule such as the following: when the runtime observes that an object R
> > referenced by a field of a deinitializing object O has a reference count
> > of one, it assumes that R must die when O dies and consequently puts R
> > into some moribund state from which there is no revivification.)
> > (2) If it is legal, is calling extendLifetime from a dispatch async the
> > appropriate way to do it?
> > (3) Is my "implementation" (such as it is) of extendLifetime correct?
> > (I can't use the stdlib's _fixLifetime, unfortunately, or even
> > implement extendLifetime in the same way.)
>
> Have you tried using the standard library's withExtendedLifetime(_:_:)
> function?
>
> > (4) Does optimization based on visibility enter into this? In my case
> > the AsyncHandle is fileprivate.
> > (5) Is there any entirely different approach to satisfy the following
> > requirements? (a) AsyncHandle be releasable/deinitializable on any
> > thread. (b) Handle be deinitialized only on some dispatch queue q. (c)
> > AsyncHandle has the only reference to Handle.
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-users/attachments/20170227/7718c86e/attachment.html>
More information about the swift-users
mailing list