zoul zoul - 29 days ago 18
Objective-C Question

Is it thread-safe to read an instance variable while calling a setter from another thread?

I have an object with a property:

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


I use the property in a method:

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


And the property value can be changed in another method:

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


Now, if the
-doSomethingElse
method is called from another thread while I access the license plate property using the instance variable (as seen in the
-doSomething
method), is it possible to get a segfault?

Is it possible that the
-setLicensePlate
setter releases the value stored in
_licensePlate
right before I call
-frobnicate
on it and before a new valid value is assigned? And would it help to call
[self licensePlate]
instead of using
_licensePlate
directly?

Rob Rob
Answer

If you want to enjoy the atomic behavior (which is the default behavior that you get because you didn't specify the nonatomic qualifier) of this property, you must use the getter (self.licensePlate or [self licensePlate]), not use the ivar (_licensePlate).

In general, it's usually prudent to use the getters and setters everywhere except (a) the init method; and (b) and custom accessor methods. The overhead is negligible and you avoid spectrum of potential problems ranging from atomicity, memory semantics, KVO, future-proofing code in case you customize accessor methods at some future date, etc.

But, assuming you access your property only through the accessor methods (the getters and setters), the atomic qualifier, as described by Programming with Objective-C: Encapsulating Data ensures that the pointer, itself, that you are retrieving/setting is will not be corrupted by another thread:

[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.

In answer to your question, if the other thread changes the licensePlate property, while the frobnicate method is running on the other thread, that original object will not be released until that method returns.

But to be clear, the atomic qualifier does not ensure thread safety. As the above guide goes on to warn us:

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.

So, it might be thread-safe to use frobnicate on one thread while doing other stuff on another thread, but it also might not. It depends upon all the different things that can be done with this license plate object. Because the protections offered by atomic are so minimalist, we frequently will employ some synchronization (via GCD serial queue or GCD reader-writer pattern, or via any of the synchronization methods outlined in the Threading Programming Guide: Synchronization such as locks) to coordinate interaction from different threads.