-
Notifications
You must be signed in to change notification settings - Fork 3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
SingletonPtr - name not accurate, thread-safety and initialization/destruction #2480
Comments
+1 for The initializer should probably be updated to: if (NULL == _ptr) {
singleton_lock();
if (NULL == _ptr) {
_ptr = new (_data) T();
}
singleton_unlock();
} As for destructors, can they not already call the destructor manually?
I vote for not allowing reconstructing after destructing, since I believe that requires locking over all class member functions for thread safety. |
What @geky says sounds good. Renaming sounds good to me, and both |
@geky For the sake of symmetric API it would be better to have a function which call the destructor and reset the pointer. Otherwise, what happen if the Other points that worry me with the current implementation:
About the mutex part, I have a question, it seems that we embed more and more mutexes in classes rather than outside class is it a design pattern we want to follow ? I deeply fear that it strike back, mutexes does not compose well by nature, by pilling up hidden mutexes, we just increase the risk of deadlock, lock contention Edit: apparently RTX employs priority inheritance for mutexes so priority inversion is out of the scope of inner mutexes. |
Would it be ok to reset the pointer without synchronizing against calls to the class? Otherwise the only options for synchronizing I can think of are locking over all calls to the class (very deadlock prone) or some sort of buffered RCU lock (at minimum 2x memory consumption and complex). +1 for const correctness. Unfortunately class ordering rules will prevent placement in rom while the initialized flag is there, but we can dream. |
ARM Internal Ref: IOTMORF-419 |
Thanks for the ideas @pan-. My response to your questions is below. I also created #2546 to implement these. Construction / Destruction - Ideally I would like SingletonPtr to behave the same as a global class, just one which is used lazily. This means initialized on first use and destroyed program exit but only if initialized. Since calling destructors on program exit is undefined behavior and mbed-os code never exits under normal circumstances (when main returns), the destruction probably does not matter too much. Maybe for completeness when/if initialization occurs the object is added to the list of destructors that gets called on program exit? -Because of the way the lazy initialization is done it makes it hard to pass in arguments on construction. Any ideas on how to make this easier would be appreciated. Right now this has to be done by extending the class and making a default constructor pass in the desired args. This could also be done with template parameters, but I figured adding that might lead to error prone code if the template parameters are non constant values. Depending on when the singleton is first accessed the args used in construction could be different. As for the mutex, the initial draft I had used dynamic memory and did not require a mutex as the pointer was set atomically. The problem with that is classes could get created multiple times on on first use and all but one would be destroyed. After some discussion with Chris we decided that using placement new and protecting initialization by a mutex would be less intrusive. As long as the constructors are kept simple deadlocks shouldn't be a problem. I'm open to ideas on this issue though, as both implementations that were discussed have drawbacks. |
@c1728p9 I will say if I had the option to return a reference, it would definitely help in some cases in refactoring |
I didn't think SingletonPtr was that bad. Its returns a pointer to a singleton. |
Though not a pointer to a singleton of a class, and the class itself isn't really a pointer since it contains the object and should never be copied. I like |
Should a singleton ever be copied? The class overrides the dereference operator so semantically acts like pointer to an object? I dont care that much, just pick something, document it and go with it. If there is precedent in other frameworks of the same language, follow suit. |
Ok - decision made. We have better things to do than rename things that arent that bad. I'll call bikeshed and close this out. |
The name is not accurate
The classes name
SingletonPtr
is confusing. This is not a singleton. We can create multiple instances of the same class. Therefore similar pattern in another code base is calledLazyInstance
for example.Thread safety
This is not thread-safe, is it?:
Initialization of T type
It's not clear what SingletonPtr guarantees regarding initialization of a T object.
If T is POD, its data are not initialized (at least C++03,C++98). should it be
_ptr = new (_data) T();
?The destructor for the T object
There could be a method to destroy T object (call explicitly dtor).
Code reference: https://github.com/ARMmbed/mbed-os/blob/d89c3c18f9be97880f9173e87772ea2808fa8df1/hal/api/SingletonPtr.h
@pan- @c1728p9 @geky @sg-
The text was updated successfully, but these errors were encountered: