At Tue, 1 Oct 2019 23:52:05 -0400, David Storrs wrote:
> ; main dispatcher loop in the server. Receives messages, dispatches
> to child thread for processing
> (struct file-info (hash) #:transparent)
> (define channels (make-weak-hash))
> (let loop ()
> (define msg (get-next-message)) ; e.g. (file-info "sha1-hash-of-file-X")
> (hash-set! channels (file-info-hash msg) ch)
> (thread (thunk (process-file msg ch)))))
> (loop))
>
> 1) Am I correct that this does not work? The string that came out of
> file-info-hash is not eq? to the one stored inside msg, meaning that
> it's not referenced from anywhere else, so it's going to disappear the
> moment it goes into the weak hash.
Right.
> 2) The following also would not work:
> (let loop ()
> (define msg (get-next-message))
> (define the-str (file-info-hash msg)) ;; save the value out before using
> it
> (hash-set! channels the-str ch)
> (thread (thunk (process-file msg ch)))))
> (loop))
>
> The (loop) is in tail position, so this is not a recursive call. That
> means the stack frame is cleared, so 'the-str' is not reachable and
> it's cleared from the weak hash.
Also right.
This variant would retain the hash string until `process-file`
completes:
(define the-str (file-info-hash msg))
(hash-set! channels (file-info-hash msg) ch)
(thread (thunk (process-file msg ch)
(hash-remove! channels the-str)))
In this case, it's handy that `hash-remove!` is a sensible use of
`the-str`, and that use's effect means `the-str` really must be
retained.
In cases where there's no sensible way to use a value like that, as a
last resort `void/reference-sink` from `ffi/unsafe` can ensure that a
value remains reachable.
> 2) This WOULD work:
> (let loop ()
> (define msg (get-next-message)) ; e.g. (file-info "sha1-hash-of-file-X")
> (hash-set! channels msg ch)
> (thread (thunk (process-file msg ch)))))
> (loop))
>
> In this case, 'msg' is still reachable from the processing thread, so
> it remains in the weak hash until the processing thread terminates, at
> which point it is removed from the weak hash and the corresponding
> channel is GC'd.
It depends on `process-file`. If `process-file` retains `msg` until it
is otherwise done, then yes. But if `process-file` ignores the argument
for `msg` or only uses it for the first part of its work, then `msg`
can get GCed before `process-file` returns.