I have a context which stores information about the current state. This context is defined within Python. The context cleanup is handled using weakref's finalize() method.
class Context:
def __init__(self, flags = 0):
weakref.finalize(self, release_ctx, flags)
self.flags = flags
This has worked totally fine up until this point. Recently I added a C extension which contains a C object which uses information from this context.
typedef struct {
PyObject_HEAD
C_CLASS* c_class_that_uses_info_from_py_ctx;
PyObject* py_ctx;
} PyThing;
Within PyThing's c extension init method I increment the ref count of the py_ctx that is passed in and decrement the ref count on deallocation. I was under the impression that as long as an object has a non-zero ref count it wouldn't be garbage collected. This appears to not be the full story when the program exits. Basically the issue is I need to do some cleanup within the C object which relies upon the context. However, on program exit the context is being destroyed before the C object even though the context has a non-zero ref count (the weakref finalize function release_ctx() is being called before PyThing's dealloc method even though printing out the ref count of py_ctx via Py_REFCNT within the dealloc method shows that it still has 5 references). I found a statement here https://devguide.python.org/garbage_collector/ saying that if an object is unreachable all weak references are handled first. I think this is the cause for the Context being deallocated first but am not totally sure. Is there a way to prevent this deallocation from happing until all other objects have been deallocated? I've found a few articles describing Python's cyclic garbage collection but am unsure if it relates to this problem and how it might be used to solve it if it is.