def METHOD_NAME(wait_for_lock=True):
    """This decorates a function, to prevent it being called simultaneously from
    multiple threads.  Only one locked action can happen at any given time on a
    given object.
    We use a Reentrant Lock, which means that a single thread can acquire() it
    multiple times.  This is helpful (for example if locked functions call
    other locked functions, this is OK).
    If wait_for_lock is false and an action is running, it returns immediately.
    This can be given as an argument to locked_action_decorator (which sets the
    default) or to the function when called (which overrides it).
    """
    def decorator(function):
        #the decorator is meant to be called as @locked_action_decorator()
        #so we need to return a function, which is what actually gets used
        #to modify the function we're decorating.
        @functools.wraps(function)
        def locked_action(self, *args, **kwargs):
            """Perform an action, but use a lock so only one locked action can
            happen at any time"""
            #First: make sure the lock object exists
            if not hasattr(self, "_nplab_action_lock"):
                self._nplab_action_lock = threading.RLock()
            try:
                if wait_for_lock:
                    self._nplab_action_lock.acquire() #this will wait until we can lock the device
                else:    #if "wait for lock" is false, just return false if it's busy
                    if not self._nplab_action_lock.acquire(block=False):
                        print("Could not acquire action lock, giving up.")
                        return False
                return function(self, *args, **kwargs)
            except Exception as e:
                raise e #don't attempt to handle errors, just pass them on
            finally:
                self._nplab_action_lock.release() #don't leave the thing locked
        return locked_action
    return decorator