Re: Are immutable singletons thread safe?
Re: Are immutable singletons thread safe?
- Subject: Re: Are immutable singletons thread safe?
- From: Shawn Erickson <email@hidden>
- Date: Sun, 9 May 2004 09:22:33 -0700
On May 8, 2004, at 10:22 PM, Ken Tozier wrote:
Several of my classes and categories use immutable singletons to store
stuff and I'm wondering, if these classes are used in a thread, if I
would run into problems.
It depends on what you mean by "use". The singleton creation/fetching
aspects or concurrent method calls on the singleton, etc.. If the
former you likely can avoid locking by insuring your singletons are
allocated and initialized early on before secondary thread get going.
For the later you will need to use mutexes/locks in concurrence issues
exist (shared access to data structures, etc.).
The following is an example of abstract singleton class that can be
sub-classed to make concrete singleton instances... it is something
that I am using in a project (but it hasn't been fully tested yet....).
It provides thread safe lazy initialization of singletons. Feel free to
copy, hack, improve, or ignore.
#import "FTSWAbstractSingleton.h"
#import <objc/objc-runtime.h>
@implementation FTSWAbstractSingleton
static NSMutableDictionary *s_FTSWAbstractSingleton_singletons = nil;
+ (void)initialize
{
@synchronized(self) {
if (s_FTSWAbstractSingleton_singletons == nil) {
s_FTSWAbstractSingleton_singletons = [[NSMutableDictionary
alloc] init];
}
}
}
// Should be considered private to the abstract singleton class, wrap
with a "sharedXxx" class method
+ (id)singleton
{
return [self singletonWithZone:[self zone]];
}
// Should be considered private to the abstract singleton class
+ (id)singletonWithZone:(NSZone*)zone
{
id singleton = nil;
Class class = [self class];
if (class == [FTSWAbstractSingleton class]) {
[NSException raise:NSInternalInconsistencyException
format:@"Not valid to request the abstract
singleton."];
}
@synchronized(self) {
singleton = [s_FTSWAbstractSingleton_singletons
objectForKey:class];
if (singleton == nil) {
singleton = class_createInstanceFromZone(class, 0U, zone);
if ((singleton = [singleton initSingleton]) != nil) {
[s_FTSWAbstractSingleton_singletons setObject:singleton
forKey:class];
}
}
}
return singleton;
}
// Designated initializer for instances. If subclasses override they
must call this implementation.
- (id)initSingleton
{
return [super init];
}
// Disallow the normal default initializer for instances.
- (id)init
{
[self doesNotRecognizeSelector:_cmd];
return nil;
}
//
------------------------------------------------------------------------
---------------------------------------------
// The following overrides attempt to enforce singleton behavior.
+ (id)new
{
return [self singleton];
}
+ (id)allocWithZone:(NSZone *)zone
{
return [self singletonWithZone:zone];
}
+ (id)alloc
{
return [self singleton];
}
- (id)copy
{
[self doesNotRecognizeSelector:_cmd];
return self;
}
- (id)copyWithZone:(NSZone *)zone
{
[self doesNotRecognizeSelector:_cmd];
return self;
}
- (id)mutableCopy
{
[self doesNotRecognizeSelector:_cmd];
return self;
}
- (id)mutableCopyWithZone:(NSZone *)zone
{
[self doesNotRecognizeSelector:_cmd];
return self;
}
- (unsigned)retainCount
{
return UINT_MAX;
}
- (oneway void)release
{
}
- (id)retain
{
return self;
}
- (id)autorelease
{
return self;
}
- (void)dealloc
{
[self doesNotRecognizeSelector:_cmd];
}
//
------------------------------------------------------------------------
---------------------------------------------
@end
Example of a sub-class....
@interface FTSWSerialPortRegistry : FTSWAbstractSingleton
...
@implementation FTSWSerialPortRegistry
+ (FTSWSerialPortRegistry*)sharedRegistry
{
static FTSWSerialPortRegistry *s_FTSW_sharedSerialPortRegistry =
nil;
@synchronized(self) {
if (s_FTSW_sharedSerialPortRegistry == nil) {
s_FTSW_sharedSerialPortRegistry = [self singleton];
}
}
return s_FTSW_sharedSerialPortRegistry;
}
- (id)initSingleton
{
if (self = [super initSingleton]) {
knownPorts = [[NSMutableDictionary alloc] initWithCapacity:2];
currentPorts = [[NSMutableDictionary alloc] initWithCapacity:2];
[self setDynamicDiscovery:YES];
}
return self;
}
-Shawn
_______________________________________________
cocoa-dev mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored.