做什么 atomicnonatomic 财产声明中的意思?

@property(nonatomic, retain) UITextField *userName;
@property(atomic, retain) UITextField *userName;
@property(retain) UITextField *userName;

这三者在操作上有什么区别呢?

有帮助吗?

解决方案

最后两个是相同的; “原子”是默认行为(<击>注意,它实际上不是一个关键字;它只是由不存在nonatomic 的指定 - atomic加入作为关键字在最新版本的LLVM /铛的)。

假设你@synthesizing的方法实施方式中,原子与非原子的变化生成的代码。如果你正在写自己的setter / getter方法,原子/非原子/保留/分配/副本只是劝告。 (注:现在@synthesize是在最近版本的LLVM的默认行为,也没有必要宣布实例变量,它们将被自动合成,也和将有一个前缀_对他们的名字,以防止意外的直接访问。)。

使用“原子”,将合成的设定器/吸气剂将确保一个值总是从吸气退回或设置由设定器,设定器不论活性的任何其他线程。也就是说,如果线程A是在吸气的中途,同时线程B调用设置器,一个实际可行的值 - 的自动释放物体,最有可能的 - 将被返回到所述的呼叫方

nonatomic,没有这样的保证制成。因此,nonatomic比 “原子”。

相当快

什么“原子”做的不可以做的是作出关于线程安全的任何保证。如果线程A与线程B同时调用getter和C调用具有不同值的设定器,线程A可以得到三个值中的任一个返回 - 所述一个之前的任何设置器被调用或任传递到设置器的值的在B和C同样地,对象可以与来自B或C,没有办法知道的值结束。

确保数据完整性 - 的多线程编程的主要挑战之一。 - 通过其它手段来实现

添加到这样的:

单个属性的atomicity也不能保证线程安全当多个相关属性在起作用。

考虑:

 @property(atomic, copy) NSString *firstName;
 @property(atomic, copy) NSString *lastName;
 @property(readonly, atomic, copy) NSString *fullName;

在这种情况下,线程A可以是通过调用setFirstName:,然后调用setLastName:重命名的对象。在此期间,线程B可以调用fullName在线程A的两个电话之间,并会收到再加上老姓的新名字。

要解决这个问题,你需要的交易模式的。即一些其他种类的同步和/或排除的,其允许同时从属属性正在更新一个排除访问fullName

其他提示

这是Apple的文档中解释,但下面是什么是实际发生的一些例子。请注意,没有“原子”的关键字,如果你不指定“非原子”,那么该属性是原子,但指定的“原子”明确将导致错误。

//@property(nonatomic, retain) UITextField *userName;
//Generates roughly

- (UITextField *) userName {
    return userName;
}

- (void) setUserName:(UITextField *)userName_ {
    [userName_ retain];
    [userName release];
    userName = userName_;
}

现在,原子变体是一个比较复杂:

//@property(retain) UITextField *userName;
//Generates roughly

- (UITextField *) userName {
    UITextField *retval = nil;
    @synchronized(self) {
        retval = [[userName retain] autorelease];
    }
    return retval;
}

- (void) setUserName:(UITextField *)userName_ {
    @synchronized(self) {
      [userName_ retain];
      [userName release];
      userName = userName_;
    }
}

基本上,原子版本必须采取的锁以保证线程安全,并且还碰撞使得对象保证呼叫者存在的对象上的引用计数(和自动释放计数,以平衡的话) ,否则有一个潜在的竞争条件如果另一个线程设置的值,从而使ref计数下降到0。

实际上有大量的这些事情的工作如何取决于属性是否是标值或对象的不同变体的,以及如何保留,复制,只读,非原子等相互作用。属性一般合成只是知道该怎么做“正确的事”的所有组合。

原子

  • 是默认行为
  • 将确保当前进程在另一个进程访问变量之前由 CPU 完成
  • 速度并不快,因为它确保该过程完全完成

非原子

  • 不是默认行为
  • 更快(对于合成代码,即使用@property和@synthesize创建的变量)
  • 不是线程安全的
  • 当两个不同的进程同时访问同一个变量时可能会导致意外的行为

理解上的差异是使用以下实施例中的最佳方式。

假设有称为“名称”的原子字符串属性,并且如果从线程A调用[self setName:@"A"],呼叫从线程B [self setName:@"B"],并调用从线程C- [self name],然后在不同线程上的所有操作将被连续执行,这意味着,如果一个线程正在执行一个调节器或吸气,然后其他线程将等待。

这使得“名称”属性读/写安全的,但如果另一个线程,d,调用[name release]同时则是因为没有这里涉及的setter /吸气调用此操作可能会产生崩溃。这意味着将对象读/写安全(原子),但不是线程安全作为另一个线程可以同时发送任何类型的消息到该对象。显影剂应确保这样的对象线程安全。

如果将属性“名称”是非原子,然后在上面的例子中的所有线程 - A,B,C和d将执行同时产生任何不可预知的结果。在的原子的情况下,无论是A,B或C中的一个将第一执行,但仍然d可以并行执行。

这个问题的其他优秀答案已经很好地定义了语法和语义。因为 执行表现 不太详细,我会补充我的答案。

这3个功能上有什么区别?

我一直认为原子作为默认值非常好奇。在抽象级别,我们致力于使用类的原子属性作为实现 100% 线程安全的工具,这是一种极端情况。对于真正正确的多线程程序,几乎肯定需要程序员的干预。同时,性能特征和执行尚未深入详细说明。多年来,我编写了一些大量的多线程程序,我一直将我的属性声明为 nonatomic 一直以来,因为原子对于任何目的来说都是不明智的。在讨论原子和非原子属性的细节时 这个问题, ,我做了一些分析,遇到了一些奇怪的结果。

执行

好的。我要澄清的第一件事是锁定实现是实现定义的和抽象的。路易斯使用 @synchronized(self) 在他的例子中——我认为这是一个常见的混乱根源。实施并不 实际上 使用 @synchronized(self);它使用对象级别 自旋锁. 。路易斯的插图非常适合使用我们都熟悉的结构进行高级插图,但重要的是要知道它不使用 @synchronized(self).

另一个区别是原子属性将在 getter 中保留/释放循环您的对象。

表现

这是有趣的部分:使用原子属性访问的性能 无争议的 (例如。在某些情况下,单线程)情况可能真的非常快。在不太理想的情况下,使用原子访问的开销可能是普通访问的 20 倍以上 nonatomic. 。虽然 有争议 对于三字节结构(2.2 GHz),使用 7 个线程的情况要慢 44 倍 酷睿 i7 四核,x86_64)。三字节结构是一个非常慢的属性的示例。

有趣的旁注:三字节结构的用户定义访问器比合成原子访问器快 52 倍;或合成非原子访问器速度的 84%。

有争议案件中的对象也可能超过 50 次。

由于实施中的优化和变化的数量,很难衡量这些环境中的实际影响。您可能经常听到类似“相信它,除非您分析并发现它是一个问题”。由于抽象级别的原因,实际上很难衡量实际影响。从配置文件中收集实际成本可能非常耗时,而且由于抽象,非常不准确。同样,ARC 与 MRC 可以产生很大的不同。

那么让我们退后一步, 不是 重点关注属性访问的实现,我们将包括常见的嫌疑人,例如 objc_msgSend, ,并检查许多调用的一些现实世界的高级结果 NSString 吸气剂 无争议的 情况(以秒为单位的值):

  • MRC |非原子|手动实施的getters:2
  • MRC |非原子|合成的Getter:7
  • MRC |原子|合成的Getter:47
  • 弧|非原子|合成的Getter:38(注:ARC在这里添加了引用计数循环)
  • 弧|原子|合成的Getter:47

正如您可能已经猜到的那样,引用计数活动/循环是原子和 ARC 下的重要贡献者。您还会在有争议的案件中看到更大的差异。

虽然我很注重表现,但我还是说 语义第一!. 。与此同时,对于许多项目来说,性能并不是最重要的。然而,了解您所使用的技术的执行细节和成本当然不会有什么坏处。您应该根据您的需求、目的和能力使用正确的技术。希望这将为您节省几个小时的比较时间,并帮助您在设计程序时做出更明智的决定。

<强>原子 =线程安全

<强>非原子 =否线程安全

线程安全:

实例变量是线程安全的,如果他们的行为正确地从多个线程访问时,不管由所述运行时间环境的那些线程的执行的调度或交织的,并且与在主叫的部分没有额外的同步或其他协调代码。

在我们的上下文:

如果一个线程更改实例的改变后的值是提供给所有的线程的值,并且只有一个线程可以在一个时间改变的值。

凡使用atomic

如果该实例变量是要去在多线程环境进行访问。

atomic的启示:

不一样快nonatomic因为nonatomic不需要来自运行时对任何看门狗工作。

凡使用nonatomic

如果该实例变量不是要去被多个线程改变就可以使用它。它提高了性能。

我找到了对原子和非原子属性的很好的解释 这里. 。以下是相同的一些相关文本:

“原子”意味着它不能被分解。在操作系统/编程术语中,原子函数调用是一种不能被中断的调用——整个函数必须被执行,并且在完成之前不能通过操作系统通常的上下文切换从CPU中换出。以防万一您不知道:由于 CPU 一次只能做一件事,操作系统将对 CPU 的访问权轮流分配给所有正在运行的进程(在很小的时间片内),以提供 错觉 多任务处理。CPU 调度程序可以(并且确实)在进程执行过程中的任何时刻中断进程 - 即使在函数调用中间。因此,对于更新共享计数器变量之类的操作(其中两个进程可以尝试同时更新变量),它们必须“原子”执行,即每个更新操作必须在任何其他进程交换到该变量之前完整完成。中央处理器。

所以我猜测在这种情况下,原子意味着属性读取器方法不能被中断 - 实际上意味着该方法正在读取的变量不能在中途改变它们的值,因为其他一些线程/调用/函数得到交换到CPU上。

因为 atomic 变量不能被中断,它们在任何点所包含的值都保证(线程锁) 未损坏的, 不过,确保此线程锁会使访问它们的速度变慢。 non-atomic 另一方面,变量不提供这样的保证,但确实提供了更快访问的奢侈。总结一下, non-atomic 当您知道您的变量不会同时被多个线程访问并加快速度时。

在阅读了这么多文章、Stack Overflow 帖子并制作了演示应用程序来检查可变属性属性后,我决定将所有属性信息放在一起:

  1. atomic // 默认
  2. nonatomic
  3. strong = retain // 默认
  4. weak = unsafe_unretained
  5. retain
  6. assign // 默认
  7. unsafe_unretained
  8. copy
  9. readonly
  10. readwrite // 默认

文章中 iOS 中的可变属性属性或修饰符 您可以找到上述所有属性,这一定会对您有所帮助。

  1. atomic

    • atomic 表示只有一个线程访问该变量(静态类型)。
    • atomic 是线程安全的。
    • 但它的性能很慢
    • atomic 是默认行为
    • 非垃圾收集环境中的原子访问器(即当使用保留/释放/自动释放时)将使用锁来确保另一个线程不会干扰值的正确设置/获取。
    • 它实际上不是一个关键字。

    例子:

        @property (retain) NSString *name;
    
        @synthesize name;
    
  2. nonatomic

    • nonatomic 表示多线程访问变量(动态类型)。
    • nonatomic 是线程不安全的。
    • 但它的性能很快
    • nonatomic 不是默认行为。我们需要添加 nonatomic property 属性中的关键字。
    • 当两个不同的进程(线程)同时访问同一个变量时,可能会导致意外的行为。

    例子:

        @property (nonatomic, retain) NSString *name;
    
        @synthesize name;
    

原子

访问到属性

原子的保证将在原子方式执行。例如。它总是返回一个完全初始化的对象,任何的get / set属性的一个线程必须完成之前,另一个可以访问它。

如果你想象一次你可以看到为什么结果会不漂亮的两个线程出现以下功能。

-(void) setName:(NSString*)string
{
  if (name)
  {
    [name release]; 
    // what happens if the second thread jumps in now !?
    // name may be deleted, but our 'name' variable is still set!
    name = nil;
  }

  ...
}

<强>优点: 完全初始化的对象的回报每次使得它最好选择在多线程的情况下

<强>缺点: 性能损失,使得执行较慢的小

<强>非原子:

不像原子,它并不能保证完全初始化的对象返回各一次。

<强>优点: 极快的执行。

<强>缺点: 在多线程的情况下,垃圾值的机会。

最简单的答案第一:有你的第二个两个例子之间没有什么区别。默认情况下,属性访问是原子的。

在非垃圾收集环境原子存取(即,使用时保留/释放/自动释放)将使用一个锁,以确保另一个线程不与正确的设置干扰/获取的值的

参见“性能和线程”部分。

原子是指只有一个线程访问变量(静态类型)。原子是线程安全的,但它是缓慢的。

非原子是指多个线程访问变量(动态型)。非原子是线程不安全的,但它是快速。

原子是的线程安全下,它是的并它的公保证(不保证)只有锁定值被提供无论多少个线程试图在同一区域进行访问。当使用原子,一片该函数内写入的代码变得临界区的部分中,向其中只有一个线程可以在同一时间执行。

它仅仅保证线程安全;它并不能保证。 我的意思是你雇佣一个老练的驾驶员为你的车,它仍然不保证汽车不会满足事故。然而,概率保持丝毫。

原子 - 它不能被分解,所以结果的预期。与非原子 - 当另一个线程存取的存储区它可以修改它,所以结果是出乎意料的

代码讲座:

原子使财产线索的getter和setter安全。例如如果u已经写:

self.myProperty = value;

是线程安全的。

[myArray addObject:@"Abc"] 

不是线程安全。

默认atomic, ,这意味着每当您使用该属性时,它都会降低性能,但它是线程安全的。Objective-C 所做的是设置一个锁,因此只要执行 setter/getter,只有实际线程可以访问该变量。

具有 ivar _internal 的属性的 MRC 示例:

[_internal lock]; //lock
id result = [[value retain] autorelease];
[_internal unlock];
return result;

所以最后两个是相同的:

@property(atomic, retain) UITextField *userName;

@property(retain) UITextField *userName; // defaults to atomic

另一方面确实 nonatomic 不向您的代码添加任何内容。因此,只有您自己编写安全机制,它才是线程安全的。

@property(nonatomic, retain) UITextField *userName;

关键字根本不必写为第一个属性。

不要忘记,这并不意味着该属性作为一个整体是线程安全的。只有setter/getter的方法调用是。但是如果你在 2 个不同的线程中同时使用 setter 和 getter,它也可能会被破坏!

  

原子(默认)

     

原子是默认的:如果你不输入任何内容,你的财产是   原子。原子属性保证,如果你试图从读   它,你会得到一个有效的值。它不作任何保证   什么该值可能是,但你会得到很好的数据,而不是   只是垃圾内存。这是什么让你做的是,如果你有多个   线或在一个单可变指向多个进程,一个   线程可以读取和另一个线程可以写。如果他们打在同一   时间,读线程是保证获得两个值之一:   之前更改或变更后。什么原子不   给你的是任何形式的保证哪个这些值的你   可能会。原子是真正通常与是线程安全的困惑,   那是不正确的。你需要保证你的线程安全   其他方法。然而,原子将保证,如果你试图阅读,   你回来某种价值。

     

非原子

     

在另一面,非原子,因为你可能猜测,只是意味着,   “不这样做,把原子的东西。”你失去的是保证你   总是回来的东西。如果试图在一个中间读   写,你能拿回来的垃圾数据。但是,在另一方面,你去   得快一点。由于原子的性质必须做一些魔术   保证你会得到一个值,他们有点慢。如果   它是你访问了很多的属性,你可能要下降   到非原子,以确保您不会招致这样的速度   罚。

请参阅更这里: https://realm.io/news/tmi-objective-c-属性的属性/

如果你正在使用你的财产在多线程代码,那么你就能够看到非原子和原子属性之间的区别。非原子比原子和原子是线程安全更快,不非原子。

Vijayendra特里帕西已经给出用于多线程环境中的示例。

  • -Atomic 表示只有一个线程访问该变量(静态类型)。
  • - 原子是线程安全的。
  • -但它的性能很慢

如何申报:

由于原子是默认的,所以,

@property (retain) NSString *name;

AND 在实施文件中

self.name = @"sourov";

假设与三个属性相关的任务是

 @property (retain) NSString *name;
 @property (retain) NSString *A;
 @property (retain) NSString *B;
 self.name = @"sourov";

所有属性并行工作(如异步)。

如果您从线程中调用“name” A,

同时如果你打电话

[self setName:@"Datta"]

从线程 ,

现在如果 *name 属性是非原子的 然后

  • 它将返回 A 的值“Datta”
  • 它将返回 B 的值“Datta”

这就是为什么非原子被称为线程不安全但是因为并行执行所以性能很快

现在如果 *name 属性是原子的

  • 它将确保 A 的值“Sourov”
  • 然后它将返回 B 的值“Datta”

这就是为什么atomic被称为线程安全的原因这就是为什么它被称为读写安全

这种情况操作会串行执行。 并且性能缓慢

- 非原子意味着多线程访问变量(动态类型)。

- 非原子是线程不安全的。

- 但它的性能很快

-Nonatomic不是默认行为,我们需要在property属性中添加nonatomic关键字。

因为在迅速确认迅速的特性在OBJC意义上是非原子。原因之一是您需要考虑每个属性的原子性是否足以满足您的需求。

参考: https://forums.developer.apple.com/thread/25642

如需更多信息,请访问网站http://rdcworld-iphone.blogspot.in/2012/12/variable-property-attributes-or.html

在你开始之前:您必须知道,内存中的每个对象都需要从内存中释放,以便新的编写器发生。你不能像在纸上那样简单地在某物上书写。你 必须 首先擦除(dealloc)它,然后你可以写入它。如果此时擦除已完成(或完成一半)并且没有任何内容 还没有 已写(或写了一半),而您尝试阅读它可能会出现很大问题!原子和非原子可以帮助您以不同的方式处理这个问题。

初读 提问然后阅读 布姆的回答. 。另外,再看看我的总结。


atomic 将永远保证

  • 如果两个不同的人想同时读书和写作,你的论文就不会被烧毁!--> 即使在竞争条件下,您的应用程序也永远不会崩溃。
  • 如果一个人正在尝试写,并且只写了 8 个字母中的 4 个,那么中间就无法读取,只有在写完所有 8 个字母后才能进行读取 --> 不会发生 read(get) “仍在写入的线程”,即如果有8个字节到多个字节要写入,而只写入了4个字节——到那时,你就不允许从中读取。但既然我说它不会崩溃,那么它会读取一个值 自动释放 目的。
  • 如果 写信给你 擦掉了之前写在纸上的东西,然后有人想读你的书 还在读。如何?您将从类似于 Mac OS 垃圾箱的内容中读取内容(因为垃圾箱尚未 100% 擦除...它处于不确定状态) ---> 如果 ThreadA 要读取,而 ThreadB 已经释放写入,您将得到来自 ThreadB 最终完全写入的值的值或从自动释放池中获取的值。

保留计数是 Objective-C 中管理内存的方式。当您创建一个对象时,它的保留计数为 1。当您向对象发送保留消息时,其保留计数会增加1。当您向对象发送发布消息时,其保留计数会减少1。当您发送对象时 自动释放消息, ,将来的某个阶段将其保留数量减少1。如果对象的保留计数减少到0,则将其划分。

  • 原子 保证线程安全,尽管它对于实现线程安全很有用。线程安全与您如何编写代码/您正在读取/写入哪个线程队列有关。它仅保证多线程不崩溃。

什么?!是多线程和 线程安全 不同的?

是的。多线程意味着:多个线程可以同时读取共享数据,并且我们不会崩溃,但它不能保证您不会读取非自动释放的值。有了线程安全,就可以保证你读到的内容不会被自动释放。默认情况下,我们不将所有内容设为原子的原因是,存在性能成本,而且对于大多数事情来说,并不真正需要线程安全。我们代码的某些部分需要它,对于这几个部分,我们需要使用锁、互斥锁或同步以线程安全的方式编写代码。


nonatomic

  • 由于没有像 Mac OS 垃圾箱这样的东西,所以没有人关心你是否总是得到一个值(<-- 这可能会导致崩溃),也没有人关心是否有人试图读到你写的一半(尽管中途写在内存中与中途写在纸上有很大不同,在内存中它可能会给你一个以前疯狂愚蠢的值,而在纸上你只能看到一半的内容) - >不保证不会崩溃,因为它不使用自动释放机制。
  • 不保证读取完整的写入值!
  • 比原子更快

总体而言,它们在两个方面有所不同:

  • 是否因有或没有自动释放池而崩溃。

  • 允许在“尚未完成写入或空值”的中间读取,或者不允许且仅允许在该值是时读取 完全 书面。

的原子属性确保到不论多少线程正在做的吸气及设定器在其上保留一个完全初始化的值。

在非原子属性指定合成访问器简单地设置或直接返回一个值,与没有关于如果该相同值从不同的线程同时访问会发生什么的保证。

原子是指只有一个线程可以在同一时间(静态类型)访问变量。原子是线程安全的,但它是缓慢的。

非原子意味着多个线程可以在同一时间(动态型)访问变量。非原子是线程不安全的,但它是快速。

<强> 原子性 原子(默认)

  

原子是默认的:如果你不输入任何内容,你的财产是   原子。原子属性保证,如果你试图从读   它,你会得到一个有效的值。它不作任何保证   什么该值可能是,但你会得到很好的数据,而不是   只是垃圾内存。这是什么让你做的是,如果你有多个   线或在一个单可变指向多个进程,一个   线程可以读取和另一个线程可以写。如果他们打在同一   时间,读线程是保证获得两个值之一:   之前更改或变更后。什么原子不   给你的是任何形式的保证哪个这些值的你   可能会。原子是真正通常与是线程安全的困惑,   那是不正确的。你需要保证你的线程安全   其他方法。然而,原子将保证,如果你试图阅读,   你回来某种价值。

<强> 非原子

  

在另一面,非原子,因为你可能猜测,只是意味着,   “不这样做,把原子的东西。”你失去的是保证你   总是回来的东西。如果试图在一个中间读   写,你能拿回来的垃圾数据。但是,在另一方面,你去   得快一点。由于原子的性质必须做一些魔术   保证你会得到一个值,他们有点慢。如果   它是你访问了很多的属性,你可能要下降   到非原子,以确保您不会招致这样的速度   罚款。访问

https://academy.realm.io/posts / TMI-目标c-属性的属性/

<强>原子性属性的属性(原子和非原子)不被反映在对应的夫特属性声明,但Objective-C的实施原子性保证时导入的特性选自夫特访问仍然保持。

<强>因此 - 通过夫特使用时如果定义在Objective-C的原子属性它仍将原子

礼貌 https://medium.com/@YogevSitton/原子-VS-非原子 - 属性 - 碰撞航向d11c23f4366c

如果您使用的是原子,这意味着该线程将是安全的,只读的。如果您正在使用非原子,这意味着多个线程访问的变量,是线程不安全的,但它正迅速执行,做了读取和写入操作;这是动态类型。

事实是,他们使用自旋锁来实现原子属性。如以下的代码:

 static inline void reallySetProperty(id self, SEL _cmd, id newValue, 
      ptrdiff_t offset, bool atomic, bool copy, bool mutableCopy) 
    {
        id oldValue;
        id *slot = (id*) ((char*)self + offset);

        if (copy) {
            newValue = [newValue copyWithZone:NULL];
        } else if (mutableCopy) {
            newValue = [newValue mutableCopyWithZone:NULL];
        } else {
            if (*slot == newValue) return;
            newValue = objc_retain(newValue);
        }

        if (!atomic) {
            oldValue = *slot;
            *slot = newValue;
        } else {
            spin_lock_t *slotlock = &PropertyLocks[GOODHASH(slot)];
            _spin_lock(slotlock);
            oldValue = *slot;
            *slot = newValue;        
            _spin_unlock(slotlock);
        }

        objc_release(oldValue);
    }

原子性质: - 当与原子属性,这意味着它只有一个线程访问,这将是线程安全的,将是性能的角度好,将有默认的行为分配一个变量

非原子属性: - 当原子属性分配一个变量,这意味着它具有多线程访问,它不会是线程安全的,在性能的角度看慢,将有默认的行为,当两个不同的线程想在同时访问变量它会给意外的结果。

要简化整个混乱,让我们了解互斥锁。

互斥锁,按名称,锁定对象的可变性。因此,如果目的是通过一类访问,而任何其他类别可以访问相同的对象。

在的iOS,@sychronise还提供互斥锁。现在它用于在FIFO模式,并确保流动不受两个类共享相同的实例。然而,如果该任务是在主线程,使用原子性质,因为它可以保持你的UI和降低性能避免访问对象。

原子:通过锁定使用NSLOCK螺纹确保线程安全

非原子:不保证线程安全,因为没有线程锁定机构

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top