colesbury / nogil-3.12

Multithreaded Python without the GIL (experimental rebase on 3.12)
Other
143 stars 7 forks source link

Questions on INCREF/DECREF synchronization #14

Closed MichaelSuen-thePointer closed 9 months ago

MichaelSuen-thePointer commented 9 months ago

-- This is not an official python repo so I put discussion here. --

I've just read your PEP on biased ref counting. After reading the code, I have a few question on synchronization of inc/dec ref.

Assuming the following situation:

My question is, is it possible that the INCREF to the shared refcnt not visible to the owning-thread yet, causing its checking on shared refcnt returns zero, then erroneously free the object?

colesbury commented 9 months ago

In general, you must already hold a strong reference to an object before you incref it. A notable exception is weak references, which can create a strong reference from a non-owning reference. They require special handling. When we first create a weak reference to an object, we set the _Py_REF_MAYBE_WEAKREF flag on the shared refcount. This disables the fast-path deallocation: if _Py_REF_MAYBE_WEAKREF is set (or _Py_REF_QUEUED or _Py_REF_MERGED), the owning thread goes through the "slow" deallocation path, which involves an atomic cmpxchg on the shared refcount, synchronizing with any thread that is trying to incref.

The dict and list accesses that avoid locking have similar requirements. They set the _Py_REF_MAYBE_WEAKREF flag the first time a non-owning thread attempts to load an object (and that happens under the dict or list lock).

colesbury commented 9 months ago

Here is the slow path for reference:

https://github.com/colesbury/nogil-3.12/blob/cedde4f5ec3759ad723c89d44738776f362df564/Objects/object.c#L2488-L2504

MichaelSuen-thePointer commented 9 months ago

I see, thank you for the explanation.