问题
To make use of global variables and methods I implemented Singleton as a healthy coding practice. I followed Apple documents, john wordsworth blog before implementing it. In the first, I did not make my singleton thread safe and I implemented this method along with all other mentioned in the blog and Apple document.
+ (SingletonClass *)sharedManager
{
static SingletonClass *sharedManager = nil;
if (sharedManager == nil) {
sharedManager = [[super allocWithZone:NULL] init];
}
return sharedManager;
}
After that to make Singleton thread safe I made changes to + (SingletonClass *)sharedManager
class like this and my app stops launching. I put break points and observed dispatch_once
gets called twice and then code stops executing further.
+(SingletonClass *)sharedManager
{
static SingletonClass *sharedManager = nil;
if (sharedManager !=nil)
{
return sharedManager;
}
static dispatch_once_t pred;
dispatch_once(&pred, ^{
sharedManager = [SingletonClass alloc];
sharedManager=[sharedManager init];
});
return sharedManager;
}
If i remove this thread safe code snippet and revert back to previous code it works fine and code gets executed.
Please note that I also looked at the bbum's answer here in which he has mentioned possible deadlock situation before asking question but I am not able to figure out the issue. Any explanation or solution will be helpful for me. Thanks.
Edit 1:
In case someone wants to look at the complete code, I have created gist for that. Please follow there. Thanks.
回答1:
Let's consider what happens if two threads call second version of sharedManager
almost simultaneously.
Thread 1 calls first. It checks sharedManager !=nil
, which is false, so it goes on to the dispatch_once
. In the dispatch_once
block, it executes [SingletonClass alloc]
and stores the result in sharedManager
.
Now, before thread 1 continues on to the next line, thread 2 comes along and calls sharedManager
. Thread 2 checks sharedManager !=nil
, which is now true. So it returns sharedManager
, and the caller then tries to use sharedManager
. But at this time, sharedManager
hasn't been fully initialized yet. That's bad.
You cannot set sharedManager
until you have a fully initialized object to set it to. Also (as borrrden pointed out), you don't need the sharedManager !=nil
check at the top, because dispatch_once
is very efficient anyway.
+ (SingletonClass *)sharedManager {
static dispatch_once_t pred;
static SingletonClass *sharedManager;
dispatch_once(&pred, ^{
sharedManager = [[SingletonClass alloc] init];
});
return sharedManager;
}
Now, I've looked at your gist and your problem is here:
+ (id)allocWithZone:(NSZone*)zone {
return [[self sharedManager] retain];
}
Your +[SingletonClass sharedManager]
method calls +[SingletonClass alloc]
in the dispatch_once
block. Since you don't override alloc
, +[SingletonClass alloc]
calls +[SingletonClass allocWithZone:NULL]
. And +[SingletonClass allocWithZone:]
method calls +[SingletonClass sharedManager]
. On this second call to sharedManager
, your program hangs in dispatch_once
, because you're still inside the first call to dispatch_once
.
The simplest fix is to remove your implementation of allocWithZone:
. Just document that sharedManager
is the only supported way to get an instance of SingletonClass
and move on.
If you want to be obtuse and make [[SingletonClass alloc] init]
return the singleton, even if you do it repeatedly, it's complicated. Don't try to override alloc
or allocWithZone:
. Do this:
static SingletonClass *sharedManager; // outside of any method
+ (SingletonClass *)sharedManager {
return sharedManager ? sharedManager : [[SingletonClass alloc] init];
}
- (id)init {
static dispatch_once_t once;
dispatch_once(&once, ^{
if (self = [super init]) {
// initialization here...
sharedManager = self;
}
});
self = sharedManager;
return self;
}
回答2:
You don't need the check on the top, get rid of the if
statement. The dispatch_once
guarantees that the block will only be executed once in the lifetime of the application so the first check is redundant.
More Info: http://cocoasamurai.blogspot.jp/2011/04/singletons-your-doing-them-wrong.html
来源:https://stackoverflow.com/questions/14192140/code-execution-stops-on-using-thread-safe-singleton-initialization-code