Open pganssle opened 6 years ago
Hi @pganssle, hmm this is pretty unfortunate, but possibly a bit out-of-scope for lazy_static
to support. I think the semantic differences are a bit too subtle for us to support both approaches, and there are equal drawbacks to duplicated effort where other side-effects are involved in the initialization.
Have you already worked around this in your code?
@KodrAus Yes, I took effectively the same approach lazy_static
does, implementing Deref
on a "dummy struct", but locking around the assignment rather than the execution of the block that returns the value I want. See here.
I totally understand if it's out of scope, it's a pretty unusual situation.
@pganssle Glad to hear you found your way around it :+1:
Something I think we could do better is describe how values are initialized in the docs better. We have this section on implementation details, but it's pretty light in details.
I have been working on a wrapper of Python's
datetime
library, which has a one-time initialization of an API object. I felt thatlazy_static
gave the best semantics, but it turns out it can cause deadlocks when used in multiple threads if the stuff inside thelazy_static
acquires locks.In my example, I have:
The
PyDateTimeAPI
is only accessed within functions that have acquired the global interpreter lock (GIL), butPyDateTime_IMPORT()
releases and then re-acquires the GIL. This causes a deadlock as such:lazy_static
locklazy_static
lockimport
call and blocks on GILIn this case, I happen to know that the code I'm calling is already thread-safe, and the value of
PyDateTime_IMPORT()
is guaranteed by contract to return the same object on a subsequent call.Is it possible to get a version of
lazy_static
that does not attempt to acquire a lock? Having it be unsafe is also fine.Another option might be that the no-lock version of
lazy_static
doesn't lock around the function body, but does lock around assigning the value. In pseudocode it would be something like this:So long as the function body has no side effects, the worst case scenario is duplicated effort.
I'd be fine if the macro were only available in unsafe blocks.