Stream design with ARC

First of all, let me quote the chapter in the Apple Threading Programming Guide:

Recognize code validation threats

When using locks and memory barriers, you should always carefully place them in your code. Even locks that seem well placed can actually lull you into a false sense of security. The following series of examples attempt to illustrate this problem by pointing out flaws in the seemingly harmless code. The basic premise is that you have a mutable array containing a set of immutable objects. Suppose you want to call the method of the first object in an array. You can do this using the following code:

NSLock* arrayLock = GetArrayLock(); NSMutableArray* myArray = GetSharedArray(); id anObject; [arrayLock lock]; anObject = [myArray objectAtIndex:0]; [arrayLock unlock]; [anObject doSomething]; 

Since the array is modified, locking around the array prevents other threads from changing the array until you get the desired object. And also because the object you are retrieving is itself immutable, locking is not necessary to call the doSomething method.

However, there is a problem with the previous example. What happens if you release the lock and another thread enters and removes all the objects from the array before you can execute the doSomething method? In an application without garbage collection, the object that holds your code can be released, leaving the object pointing to an invalid memory address. To fix the problem, you may decide to simply rebuild your existing code and release the lock after your doSomething call, as shown here:

 NSLock* arrayLock = GetArrayLock(); NSMutableArray* myArray = GetSharedArray(); id anObject; [arrayLock lock]; anObject = [myArray objectAtIndex:0]; [anObject doSomething]; [arrayLock unlock]; 

By moving the doSomething call inside the lock, your code ensures that the object is still valid when the method is called. Unfortunately, if the doSomething method is time consuming, it can cause your code to hold the lock for a long time, which can create a performance bottleneck.

The problem with the code is not that the critical area was bad, but that the actual problem was not understood. The reality of the problem is the memory management problem, which only triggers the presence of other threads. Because it can be released by another thread, the best solution would be to save anObject before releasing the lock. This solution solves the real problem of the object being released and does so without introducing potential performance penalty.

 NSLock* arrayLock = GetArrayLock(); NSMutableArray* myArray = GetSharedArray(); id anObject; [arrayLock lock]; anObject = [myArray objectAtIndex:0]; [anObject retain]; [arrayLock unlock]; [anObject doSomething]; [anObject release]; 

And the question arises: Is there a way to solve the problem when using ARC?

+4
source share
1 answer

ARC solves this problem automatically; by default, each pointer is a strong pointer, which means that the object is guaranteed to be preserved until you do so using this pointer.

This means that whenever you get an object from an array, ARC always saves that object. This ensures its service life, even if the object is subsequently deleted from the array.

+4
source

Source: https://habr.com/ru/post/1483580/


All Articles