Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What happens if NSMutableArray is modified by multiple threads at the same time? (if the objects it contains are retained elsewhere)

I have an NSMutableArray containing many objects.

What happens if a change is made to the array, while I am making a copy of the array using [NSMutableArray arrayWithArray:someArray];

Eg: If an object an object is removed from the array while the copy is being made?

I'm not sure how to test this scenario.

EDIT: The objects are not released (as they are retained elsewhere). I just use this array as a lookup table.

like image 314
xcoder Avatar asked Sep 06 '11 11:09

xcoder


People also ask

What will happen if multiple threads accessing the same resource?

Multiple threads accessing shared data simultaneously may lead to a timing dependent error known as data race condition. Data races may be hidden in the code without interfering or harming the program execution until the moment when threads are scheduled in a scenario (the condition) that break the program execution.

Is NSMutableArray thread-safe?

In general, the collection classes (for example, NSMutableArray , NSMutableDictionary ) are not thread-safe when mutations are concerned. That is, if one or more threads are changing the same array, problems can occur.

What is NSMutableArray?

The NSMutableArray class declares the programmatic interface to objects that manage a modifiable array of objects. This class adds insertion and deletion operations to the basic array-handling behavior inherited from NSArray . NSMutableArray is “toll-free bridged” with its Core Foundation counterpart, CFMutableArray .

When to use threads vs processes?

Process means a program is in execution, whereas thread means a segment of a process. A Process is not Lightweight, whereas Threads are Lightweight. A Process takes more time to terminate, and the thread takes less time to terminate. Process takes more time for creation, whereas Thread takes less time for creation.


2 Answers

as you know, the container/collection is not guaranteed to be thread safe. what could happen if you change the array while copying or reading? a lot of things. the obvious cases are that it may be reallocating at the time, it may pass or return an invalid reference to you (e.g. the most recently removed), or it may access objects which have been released (from another thread). in addition to things that will make your app crash or cause other UB, it may not return correct or consistent values. it is a misinterpretation of the data. neither are good.

you don't test the scenario - threading issues are difficult to reproduce and you really can never cover all the cases. since the object itself does not guaranteee thread safety - your implementation has to restrict accesses/mutations/interactions to one thread at a time. when dealing with object which are used in multithreaded contexts: anytime you access or query information from an object's mutable state, you should guard the object (e.g. with a lock). therefore, you simply lock it while using it. lock/copy/unlock/use copy is also common. for an NSMutableArray, examples of mutable state would be all its objects and its count. its operations and mutations also use the object's mutable state, so they are restricted.

if you only use this object from one thread, then obviously don't need to lock it. this is also a reason why passing by copy and holding immutable variants are both good ideas in most cases. you don't need a lock for each object, a guard for the object which holds it is often a good way to design a class for thread safety.

Update

...What happens? Does the copy contain all 5 objects (since they are retained elsewhere anyway? Do they contain 4? (even containing 4 is sufficient for me) Is an exception thrown ?

if you have not properly guarded the collection, it's as good as undefined behavior and you're lucky if it crashes.

you need to take the appropriate precautions to avoid undefined behavior. your program is operating in that domain when it's not properly guarded.

to elaborate: retaining the objects externally only reduces the probability of undefined behave\ior, but it certainly does not eliminate it. more examples of consequences include exceptions, segfaults, reading or writing memory which is used as another active allocation (which may show up as very mysterious issues which may also be virtually impossible to reproduce).

i encourage you to guard properly or take another approach. UB is EVIL :)

like image 131
justin Avatar answered Dec 04 '22 21:12

justin


From Apple's Docs:

Mutable objects are generally not thread-safe. To use mutable objects in a threaded application, the application must synchronize access to them using locks. (For more information, see “Atomic Operations”). In general, the collection classes (for example, NSMutableArray, NSMutableDictionary) are not thread-safe when mutations are concerned. That is, if one or more threads are changing the same array, problems can occur. You must lock around spots where reads and writes occur to assure thread safety.

Also from Apple's Docs:

Although “atomic” means that access to the property is thread-safe, simply making all the properties in your class atomic does not mean that your class or more generally your object graph is “thread-safe”—thread safety cannot be expressed at the level of individual accessor methods. For more about multithreading, see Threading Programming Guide.

like image 37
sosborn Avatar answered Dec 04 '22 22:12

sosborn