Problem
I have been trying to create a Thread Safe SingletonClass as a module that can be reused by importing as a module
in other python scripts. More like import and use it
as a metaclass for the class that you want to make it as singleton.
But however when I run my program I run into a deadlock situation where other classes that import the module waits for some one before them who had used it as a metaclass to release. I understand I am missing a great piece of basics of python related to importing and namespace possibly and thats the reason I am unable to understand this. I have gone through the following articles before about singleton in general but I think this problem is related to imports than anything else.
Link : Creating a singleton in Python
Would be great if someone can point out the mistake in this and give a possible method to have it as a reusable module / give links to external article that can help me solve this. Let me know if this idea of mine will work or is it flawed. That will really help understand the basics properly.
My folder structure and corresponding code is given below.
The following is my folder structure with the corresponding code in each file.
.
├── A.py
├── B.py
├── C.py
└── ThreadSafeSingleton.py
0 directories, 4 files
Code
ThreadSafeSingleton.py
import threading
import logging
logger= logging.getLogger(__name__)
class ThreadSafeSingletonClass(type):
# Taken from: https://stackoverflow.com/a/51897195 :)
_instances = {}
_singleton_lock = threading.Lock()
def __call__(cls, *args, **kwargs):
# double-checked locking pattern
logger.error("ThreadSafeSingletonClass : Inside __call__ of ThreadSafeSingleton")
logger.error("ThreadSafeSingletonClass : Called By"+str(cls))
if cls not in cls._instances:
logger.error("ThreadSafeSingletonClass : Trying to get lock")
with cls._singleton_lock:
logger.error("ThreadSafeSingletonClass : Got lock")
if cls not in cls._instances:
logger.error("ThreadSafeSingletonClass : Object of type" + str(cls) + " being Created")
cls._instances[cls] = super(ThreadSafeSingletonClass, cls).__call__(*args, **kwargs)
logger.error("ThreadSafeSingletonClass : Returning created Instance"+str(cls))
return cls._instances[cls]
A.py
import logging
from ThreadSafeSingleton import ThreadSafeSingletonClass
from B import B
logger=logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
class A(metaclass = ThreadSafeSingletonClass):
def __init__(self):
logger.error("A : Inside init of A")
logger.error("A : Creating object of B")
b=B()
logger.error("A: Creating object of A as part of main")
A()
logger.error("A: Returned back to A now")
logger.error("A: Exiting...")
B.py
from ThreadSafeSingleton import ThreadSafeSingletonClass
import C
import logging
logger = logging.getLogger(__name__)
class B(metaclass=ThreadSafeSingletonClass):
def __init__(self):
logger.error("B: Inside Init of B")
logger.error("B: Trying to create object of C")
c=C.C()
C.py
from ThreadSafeSingleton import ThreadSafeSingletonClass
class C(metaclass = ThreadSafeSingletonClass):
def __init__(self):
logger.error("C: We are at C Object")
Output
(env) duplex@Test:~/test/Test$ python A.py
A: Creating object of A as part of main
ThreadSafeSingletonClass : Inside __call__ of ThreadSafeSingleton
ThreadSafeSingletonClass : Called By<class '__main__.A'>
ThreadSafeSingletonClass : Trying to get lock
ThreadSafeSingletonClass : Got lock
ThreadSafeSingletonClass : Object of type<class '__main__.A'> being Created
A : Inside init of A
A : Creating object of B
ThreadSafeSingletonClass : Inside __call__ of ThreadSafeSingleton
ThreadSafeSingletonClass : Called By<class 'B.B'>
ThreadSafeSingletonClass : Trying to get lock
and it's stuck there. I am unable to understand since A is a separate singleton and B is a separate singleton, why is creation of B object dependant on someone else to release the lock ? If this is not the right way , then how can the objective of Singleton Class being reusable module be achieved.
Objective The objective is to have a singleton metaclass as a module so that any class which wants to achieve singleton just has to have it imported as part of its module and use it as a metaclass rather than defining the class each time in the each module file.
Background I am learning design patterns and have been working out on Singleton Patterns in Python. Currently I am trying to have a Thread Safe Singleton metaclass defined in a module which in turn is supposed to be imported by other classes as their own metaclass.