Replies: 1 comment
-
I understand the idea. Given the other discussions going on about finalizers, I wonder again if the right solution is expose a few lower-level operations (which definitely belong in the It isn't clear to me why one would want signature CONTEXT_FINALIZABLE =
structure Context :
sig
type 'a t
val new: (('c -> unit) -> unit) -> 'c t
end
type ('a, 'c) t
val addFinalizer: ('a, 'c) t * ('a * 'c -> unit) -> unit
val finalizeBefore: ('a, 'ca) t * ('b, 'cb) t -> unit
val new: 'a * 'c Context.t -> ('a, 'c) t
val touch: ('a, 'c) t -> unit
val withValue: ('a, 'c) t * ('a -> 'b) -> 'b and (uncontexted) finalizers would just be a specialization to a no-op context. And it seems that this could be implemented upon a lower-level set of operations that simply allowed the mutator to create different queues of pending finalizers. |
Beta Was this translation helpful? Give feedback.
-
Given many finalizers that use a common resource, there does not appear to be a way to run the finalizers as a group allowing the common resource to be used once. If use of the resource has an overhead, using the resource independently in each finalizer is inefficient. For example, the finalizers may need to obtain a common lock. In my case, the finalizers need to be scheduled in (a callback from) the application's main loop.
To provide general support for this I am using the following interface:
With this signature, a finalizable value is created in a context to allow its finalizers to be run with finalizers of other finalizable values created in the same context.
Context.new ()
.x
in a contextc
bynewInContext c x
.m
that is registered usingContext.setMarshaler c (SOME m)
will be used to run a group of finalizers of finalizable values in the contextc
asynchronously following garbage collection.c
are not run asynchronously if no marshaler is set usingContext.setMarshaler
. A marshalerm
is applied to a function that runs these finalizers usingContext.finalize c (m, doGC)
, wheredoGC
is evaluated first, typically to perform garbage collection. The marshalerm
is run synchronously. (Whether these finalizers are run synchronously depends on the marshalerm
.) Finalizers of finalizable values not in a context are also run synchronously. The result is false only if no finalizers were run betweendoGC
returning andContext.finalize
returning, i.e. without any other execution,false
indicates that evaluatingContext.finalize c (m, doGC)
again would have no effect. UsingContext.finalize c (m1, doGC)
when contextc
has a marshaler set usingContext.setMarshaler c m2
will result in one of the marshalersm1
orm2
being used but which marshaler is implementation-defined.Context.finalize
may be called where the argumentdoGC
is the identity function in which case it performs synchronous finalization only.This interface therefore allows mixing of synchronous and asynchronous finalizers.
My case was more specific as I just needed a context for each thread. For this, I am using the following interface, whose implementation is derived from an implementation of
CONTEXT_FINALIZABLE
:My MLton implementation assumes only one thread. Still, the distinction between
new
andnewInThread
is useful because the latter is used for finalization of C objects that are not thread-safe (for which the marshaler adds the finalizers to a callback from the main application loop).Beta Was this translation helpful? Give feedback.
All reactions