如何在Objective-C中创建一个线程安全的单例对象?例如,如果我有一个共享数据控制器作为单例对象,如果两个或多个线程同时访问它会发生什么?或者这些对象是否默认具有线程安全性?更新:在这种情况下,数据控制器属性内的对象是否决定其是否线程安全?例如,我的数据控制器具有NSMutableArray并且将其设置为非原子,则它将不是线程安全的。在这种情况下,它的值会发生什么?更新2:正如@synchronized(self)所做的那样?
@interface MONCookie : NSObject <NSCopying>
- (NSString *)name;
@end
@interface MONDataController : NSObject
{
@private
NSMutableArray * cookies; // << MONCookie[]
}
- (void)addCookie:(MONCookie *)cookie;
- (MONCookie *)cookieWithName:(NSString *)name;
@end
@implementation MONDataController
- (id)init
{
// no lock required here
self = [super init];
if (nil != self) {
cookies = [NSMutableArray new];
}
return self;
}
- (void)dealloc
{
// no lock required here
[cookies release], cookies = nil;
[super dealloc];
}
- (void)addCookie:(MONCookie *)cookie
{
@synchronized(self) { // now accessing cookies - lock required
[cookies addObject:cookie];
}
}
- (MONCookie *)cookieWithName:(NSString *)name
{
MONCookie * ret = nil;
@synchronized(self) { // now accessing cookies - lock required
for (MONCookie * at in cookies) {
if ([at.name isEqualToString:name]) {
ret = [at copy]; // << give them a copy if cookie is not threadsafe
}
}
}
return [ret autorelease];
}
@end
更新2
@synchronized
设置了一个对象级别的锁。您可以将其视为递归(或可重入)锁,专属于您的实例。与其他锁定方法相比,它也非常慢。上面的代码使用了它,并且是线程安全的,并等同于持有递归锁,在@synchronized
边界上进行锁定和解锁。
@interface MONCookie : NSObject <NSCopying>
{
@private
NSRecursiveLock * lock;
}
@end
@implementation MONCookie
- (id)init
{
self = [super init];
if (nil != self) {
lock = [NSRecursiveLock new];
}
return self;
}
- (void)temperatureDidIncrease
{
// ...
}
- (void)bake
{
// use the same lock for everything
// do not mix @synchronized in some places, and use of the lock
// in others. what you use to protect the data must remain consistent
//
// These are equivalent approaches to protecting your data:
{ // @synchronized:
@synchronized(self) {
[self temperatureDidIncrease];
}
}
{ // using the lock:
[lock lock];
[self temperatureDidIncrease];
[lock unlock];
}
}
@end
if(!isLocked) {
isLocked = True;
Do the stuff
isLocked = False;
}
if ([self.stringIvar isEqualToString:self.stringIvar])
。这可能会在具有或不具有原子属性的情况下失败。对于更多的实例变量和更复杂的程序,这种情况就更加棘手了。 - justinpthread_rwlock
进行了比较? - justin