objective-c - 从另一个线程调用 setter 时读取实例变量是否是线程安全的?

标签 objective-c thread-safety

我有一个带有属性的对象:

@interface Car
@property(strong) NSLicensePlate *licensePlate;
@end

我在方法中使用该属性:

- (void) doSomething {
    [_licensePlate frobnicate];
}

并且可以通过另一种方法更改属性值:

- (void) doSomethingElse {
    [self setLicensePlate:[_licensePlateDealer cleanLicensePlate]];
}

现在,如果在我使用实例变量访问车牌属性时从另一个线程调用 -doSomethingElse 方法(如 -doSomething 方法中所示),是否有可能出现段错误?

-setLicensePlate setter 是否有可能在我调用 -frobnicate 之前以及在新的操作之前释放存储在 _licensePlate 中的值?分配了有效值?调用[self licensePlate]而不是直接使用_licensePlate会有帮助吗?

最佳答案

如果您想享受此属性的 atomic 行为(这是由于您未指定 nonatomic 限定符而获得的默认行为),则必须使用 getter (self.licensePlate[self licensePlate]),而不是使用 ivar (_licensePlate)。

一般来说,谨慎的做法是在除 (a) init 方法之外的任何地方使用 getter 和 setter; (b) 和自定义访问器方法。开销可以忽略不计,并且您可以避免一系列潜在问题,包括原子性、内存语义、KVO、面向 future 的代码(以防您在将来某个日期自定义访问器方法等)。

但是,假设您仅通过访问器方法(getter 和 setter)、atomic 限定符访问您的属性,如 Programming with Objective-C: Encapsulating Data 中所述。确保您正在检索/设置的指针本身不会被另一个线程损坏:

[Atomic] means that the synthesized accessors ensure that a value is always fully retrieved by the getter method or fully set via the setter method, even if the accessors are called simultaneously from different threads.

回答您的问题,如果另一个线程更改 licensePlate 属性,而 frobnicate 方法正在另一个线程上运行,则原始对象将不会被释放直到该方法返回。

但要明确的是,atomic 限定符不能确保线程安全。正如上述指南继续警告我们的那样:

Note: Property atomicity is not synonymous with an object’s thread safety.

Consider an XYZPerson object in which both a person’s first and last names are changed using atomic accessors from one thread. If another thread accesses both names at the same time, the atomic getter methods will return complete strings (without crashing), but there’s no guarantee that those values will be the right names relative to each other. If the first name is accessed before the change, but the last name is accessed after the change, you’ll end up with an inconsistent, mismatched pair of names.

This example is quite simple, but the problem of thread safety becomes much more complex when considered across a network of related objects. Thread safety is covered in more detail in Concurrency Programming Guide.

因此,在一个线程上使用 frobnicate 而在另一个线程上执行其他操作可能是线程安全的,但也可能不是。这取决于可以使用此牌照对象完成的所有不同操作。由于原子提供的保护非常简单,因此我们经常会采用一些同步(通过 GCD 串行队列或 GCD 读写器模式,或通过 Threading Programming Guide: Synchronization 中概述的任何同步方法,例如锁)来协调不同线程的交互。

关于objective-c - 从另一个线程调用 setter 时读取实例变量是否是线程安全的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40512366/

相关文章:

objective-c - 证书签名验证失败

ios - UICollectionView 交互转换抛出异常

java - 不建议使用SingleThreadModel并不能保证线程安全,在Servlet中保证线程安全的最佳解决方案/设计方法是什么?

java - Java 中的线程安全双向关联

java - 对象的引用可以在其构造函数完成之前设置吗?

ios - 调用 takepicture 方法时 uiimagepicker 崩溃

ios - Xamarin iOS 在运行时交换包中的图像

ios - UICollectionView CustomCell - 无法取消选择已经选定的单元格

c# - 我是否需要在以下 C# 代码中使用锁定?

java - 线程安全/发布