# -*- coding: utf-8 -*-

import functools
import threading

lock = threading.Lock()


def synchronized(lock):
    """ Synchronization decorator """

    def wrapper(f):
        @functools.wraps(f)
        def inner_wrapper(*args, **kw):
            with lock:
                return f(*args, **kw)

        return inner_wrapper

    return wrapper


class Singleton(type):
    """Reference
    https://stackoverflow.com/questions/50566934/why-is-this-singleton-implementation-not-thread-safe
    """
    _instances = {}

    @synchronized(lock)
    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
        return cls._instances[cls]
