import functools


def synchronized(lock):
    """
    Synchronizes a function call access on the given lock object. `lock` must have an `acquire()` and a `release()`
    method. Function call cannot proceed until the lock is acquired. Deadlocks are possible be careful
    Args:
        lock: the lock upon which to synchronize function call access

    Returns: a decorator for wrapping a function

    """

    def decorator(fn):
        @functools.wraps(fn)
        def wrapper(*args, **kwargs):
            lock.acquire()
            try:
                return fn(*args, **kwargs)
            finally:
                lock.release()

        return wrapper

    return decorator