简体   繁体   English

objective-c中的线程安全单例对象?

[英]thread safe singleton object in objective-c?

How does one create a thread safe singleton object in objective-c. 如何在objective-c中创建线程安全的单例对象。 for eg. 例如。 If I have a shared data controller which is a singleton object what will happen if two or more threads are accessing it at the same time..? 如果我有一个共享数据控制器是一个单例对象,如果两个或多个线程同时访问它会发生什么? Or these objects have thread safety by default..? 或者这些对象默认具有线程安全性。?

update : 更新

Is it under this scenario that the objects inside the datacontroller's property decide if it is thread safe or not.. ? 是否在这种情况下,datacontroller属性中的对象决定它是否是线程安全的? Like my datacontroller has NSMutableArray and it is set nonatomic it will not be thread safe. 就像我的datacontroller有NSMutableArray并且它设置为nonatomic它不会是线程安全的。 What will happen to its value in that case? 在这种情况下,它的价值会发生什么变化?

update:2 更新:2

And what actually does @synchronized(self) do..? 实际上@synchronized(self)做了什么..?

If the data controller is not threadsafe, then undefined behavior could happen -- avoid it at all costs =) 如果数据控制器不是线程安全的,那么可能会发生未定义的行为 - 不惜一切代价避免它=)

NSObjects are definitely not threadsafe by default. 默认情况下,NSObjects绝对不是线程安全的。 Using atomic properties does not make a class threadsafe (added that because it's a popular misconception). 使用原子属性不会使类线程安全(添加因为它是一个流行的误解)。

The typical solution would involve making sure that all of your mutable state is protected with appropriate locking (eg a mutex or @synchronized ). 典型的解决方案是确保通过适当的锁定(例如互斥锁或@synchronized )保护所有可变状态。

When I say mutable state, I am referring to an object which can mutate externally or internally. 当我说可变状态时,我指的是一个可以在外部或内部发生变异的对象。 If you are not sure, lock to be sure the types are read or written from multiple threads. 如果您不确定,请锁定以确保从多个线程读取或写入类型。 This must happen at reading and writing - always. 这必须发生在阅读和写作 - 总是。 If you have a lot of reading, a readwrite lock may be a better, more specialized lock. 如果你有很多阅读,一个readwrite锁可能是一个更好,更专业的锁。

To answer in more detail, you'd have to post some code. 要更详细地回答,您必须发布一些代码。

Update 更新

Is it under this scenario that the objects inside the datacontroller's property decide if it is thread safe or not.. ? 是否在这种情况下,datacontroller属性中的对象决定它是否是线程安全的? Like my datacontroller has NSMutableArray and it is set nonatomic it will not be thread safe. 就像我的datacontroller有NSMutableArray并且它设置为nonatomic它不会是线程安全的。 What will happen to its value in that case? 在这种情况下,它的价值会发生什么变化?

Think of it as being transitive. 把它想象成具有传递性。 Your NSMutableArray, the objects it holds, and all external references to them must be used in a threadsafe manner, and you have to track all that. 你的NSMutableArray,它拥有的对象以及它们的所有外部引用必须以线程安全的方式使用,你必须跟踪所有这些。 Typically, you start by reducing what mutable state you share. 通常,您首先要减少共享的可变状态。 Instead of giving clients a reference to the array, give them copies of the elements held by the array. 而不是给客户端提供对数组的引用,而是为它们提供数组所拥有的元素的副本。 Meanwhile, protect all reads, writes, and element copying with a lock. 同时,使用锁保护所有读取,写入和元素复制。

For simplicity, I will demonstrate using @synchronize : 为简单起见,我将演示使用@synchronize

@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

Update 2 更新2

@synchronized sets up an object level lock. @synchronized设置对象级锁定。 You can think of it as a recursive (or reentrant) lock exclusive to your instance. 您可以将其视为您的实例独有的递归(或可重入)锁。 It's also quite slow compared to other locking approaches. 与其他锁定方法相比,它也很慢。 The code above uses it, and it is threadsafe and equivalent to holding a recursive lock, and locking and unlocking at the @synchronized boundaries. 上面的代码使用它,它是线程安全的,等同于持有递归锁,并在@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

I haven't programmed in objective C before but as far as i know from operating systems course, you should put a shared boolean variable in your singleton object like boolean isLocked and when every time a thread tries to access that class it should do the following. 我之前没有在目标C中编程,但据我所知,从操作系统课程中,您应该在您的单例对象中放置一个共享的布尔变量,如boolean isLocked,并且每当一个线程尝试访问该类时,它应该执行以下操作。 as i remember this is called strict alternation :) good old school days. 因为我记得这被称为严格的交替:)好老上学日。

Thread A: 线程A:

if(!isLocked) {
isLocked = True;
Do the stuff
isLocked = False;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM