Search code examples
python-multiprocessingctypes

How can a Python Ctypes Structure inside Multiprocessing Value cause a Recursion Error?


I'm trying to share a Ctypes Structure between some processes using Multiprocessing.Value(). For some reason, this one struct isn't working, and causes a random RecursionError somewhere deep inside Multiprocessing. Whats causing it? I've had no trouble making structs like this before, and its certainly not the size of something like this.

Example Program:

from ctypes import c_float, c_bool, c_int, Structure
from multiprocessing import Value

class goodStruct(Structure):
    _pack_ = 1
    _fields_ = [
        ('connected'            ,c_bool),
        ('connected_complete'   ,c_bool)
    ]

class badStruct(Structure):
    _pack_ = 1
    _fields_ = [
        ('connected'            ,c_bool),
        ('connected_complete'   ,c_bool),
        ('power_arm'            ,c_bool),
        ('power_arm_complete'   ,c_bool),
        ('slowmove'             ,c_bool),
        ('slowmove_complete'    ,c_bool),
        ('livemove'             ,c_bool),
        ('livemove_complete'    ,c_bool),
        ('end_livemove'         ,c_bool),
        ('end_livemove_complete',c_bool),
        ('error'                ,c_int),
        ('clear_error'          ,c_bool),
        ('clear_error_complete' ,c_bool),
        ('release'              ,c_bool),
        ('release_complete'     ,c_bool),
        ('stop'                 ,c_bool),
        ('stop_complete'        ,c_bool)
    ]


a = Value(goodStruct)

b = Value(badStruct)

And the output:

Traceback (most recent call last):
  File "C:\Users\e33965\Software\z_messing around\struct_test.py", line 36, in <module>
    b = Value(badStruct)
  File "C:\Users\e33965\Miniconda3\lib\multiprocessing\context.py", line 135, in Value
    return Value(typecode_or_type, *args, lock=lock,
  File "C:\Users\e33965\Miniconda3\lib\multiprocessing\sharedctypes.py", line 82, in Value
    return synchronized(obj, lock, ctx=ctx)
  File "C:\Users\e33965\Miniconda3\lib\multiprocessing\sharedctypes.py", line 122, in synchronized
    return scls(obj, lock, ctx)
  File "C:\Users\e33965\Miniconda3\lib\multiprocessing\sharedctypes.py", line 190, in __init__
    self.release = self._lock.release
  File "<string>", line 13, in setrelease
  File "<string>", line 7, in getrelease
  File "<string>", line 7, in getrelease
  File "<string>", line 7, in getrelease
  [Previous line repeated 989 more times]
  File "<string>", line 3, in getrelease
RecursionError: maximum recursion depth exceeded while calling a Python object

Solution

  • I realized the answer shortly after posting. I had a struct field called release, and when you make a Value() with a struct it adds the base level fields of the Structure as attributes of the Value() class. This class has existing methods/attributes: v.acquire( v.get_lock( v.get_obj( v.release( v.value and it was overriding the release() method. Renaming that field fixed the issue!