Hea*_*ers 5 concurrency objective-c objective-c-runtime grand-central-dispatch ios
如果我在里面创建一个单例+[NSObject initialize],我是否需要将我的代码放在一个dispatch_once块中?
static NSObject * Bar;
@implementation Foo
+ (void)initialize {
if (self == [Foo class]) {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Bar = [NSObject new];
});
}
}
@end
Run Code Online (Sandbox Code Playgroud)
编辑
我很关心这个,因为我想确保所有线程都会看到我调用Bar之后设置的+[Foo initialize].文档说+[NSObject initialize]是线程安全的,但这是否意味着它是内存安全的?
回答你直接的问题是,你不需要的dispatch_once,但是你做需要的类检查,你在那边有,因为+initialize会被调用一次,每个"非执行子"也.它只会为你关心的特定类调用一次(Foo),因此它dispatch_once是无关紧要的.Re:线程安全,该+initialize方法将在任何其他方法被分派到类(或其实例)之前完成.
但是,您没有描述所需的访问模式,因此根据您的需要,您可能希望执行相反的操作 - 如果您希望子类也可以访问Bar,那么这将是脆弱的; 如果子类在Foo它自身之前被初始化,那么类检查将阻止Bar被创建.如果您打算这种行为,那么使用dispatch_once但删除类检查 - 通常允许Bar在第一次创建Foo或初始化其任何子类时创建.(警告:当然,除非子类也会覆盖+initialize.)
Bill Bumgarner表示,这dispatch_once是苹果现在推荐的做法。
关于线程和内存安全性+initialize,感谢这篇推文,我找到了相关的运行时源来检查。objc-initialize.mm说:
* Only one thread is allowed to actually initialize a class and send
* +initialize. Enforced by allowing only one thread to set CLS_INITIALIZING.
Run Code Online (Sandbox Code Playgroud)
类可以在不同的线程上初始化,并且objc-initialize.mm有一个策略来避免它们死锁:
* +initialize deadlock case when a class is marked initializing while
* its superclass is initialized. Solved by completely initializing
* superclasses before beginning to initialize a class.
*
* OmniWeb class hierarchy:
* OBObject
* | ` OBPostLoader
* OFObject
* / \
* OWAddressEntry OWController
* |
* OWConsoleController
*
* Thread 1 (evil testing thread):
* initialize OWAddressEntry
* super init OFObject
* super init OBObject
* [OBObject initialize] runs OBPostLoader, which inits lots of classes...
* initialize OWConsoleController
* super init OWController - wait for Thread 2 to finish OWController init
*
* Thread 2 (normal OmniWeb thread):
* initialize OWController
* super init OFObject - wait for Thread 1 to finish OFObject init
*
* deadlock!
*
* Solution: fully initialize super classes before beginning to initialize
* a subclass. Then the initializing+initialized part of the class hierarchy
* will be a contiguous subtree starting at the root, so other threads
* can't jump into the middle between two initializing classes, and we won't
* get stuck while a superclass waits for its subclass which waits for the
* superclass.
Run Code Online (Sandbox Code Playgroud)
此外,类初始化状态变量由 a 保护monitor_t,它实际上定义为:
typedef struct {
pthread_mutex_t mutex;
pthread_cond_t cond;
} monitor_t;
Run Code Online (Sandbox Code Playgroud)
由于它是一个p_thread_mutex, 并且p_thread 调用实现内存屏障,因此使用起来同样安全:
static NSObject * Bar;
@implementation Foo
+ (void)initialize {
if (self == [Foo class]) {
Bar = [NSObject new];
}
}
@end
Run Code Online (Sandbox Code Playgroud)
和
static NSObject * Bar;
@implementation Foo
+ (void)initialize {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Bar = [NSObject new];
});
}
@end
Run Code Online (Sandbox Code Playgroud)