NSOperation ready but not starting on iOS 7 - ios

We created an operation framework to add some functionality not found in the base classes (e.g. tracking success/failure). Parent operations are usually non-concurrent, and may only exist to manage child operations. Child operations which are typically concurrent (downloading xml and media asynchronously).
When we run our application on iOS 7, add we a number of operations to the operation queue, ~3/4 of the operations complete, and then the app appears to hang.
When I pause the app in the debugger, and I examine the operations in the queue (sOpQueue.operations), many of them are ready to run (isReady returns TRUE), but apparently none of them are executing (isExecuting returns FALSE, and I see no evidence of any operation running on any thread).
This is a new problem as of iOS 7.
The behavior does not seem to change when I increase or decrease the number of concurrent operations.
Does anyone have any suggestions on how to determine why a ready operation is not being started?
Thanks,
Chuck

Are you issuing the isReady Key Value Observing notification?
For example, I use a property:
#property (nonatomic, getter = isReady) BOOL ready;
And then have a custom setter:
- (void)setReady:(BOOL)ready
{
[self willChangeValueForKey:#"isReady"];
_ready = ready;
[self didChangeValueForKey:#"isReady"];
}
As well as a custom getter that calls super:
- (BOOL)isReady
{
return _ready && [super isReady];
}
And, because you implemented both the setter and getter, you have to manually synthesize the property at the beginning of the #implementation (usually you don't have to do this anymore, but if you implement all of the custom accessors, you have to manually #synthesize):
#synthesize ready = _ready;
Then, the operation starts when both of the following conditions are satisfied:
The ready property is set to YES (note, use the setter, not the ivar directly);
self.ready = YES;
or
[self setReady:YES];
All other standard NSOperation criteria are satisfied (e.g. dependencies between operations, honoring maxConcurrentOperationCount, factoring in priorities, etc.).

I'll bet you have concurrent operations that haven't finished properly. Raise you number of concurrent operations and see if you can run longer before it hangs. Then figure out why your concurrent operations aren't correctly setting isFinished.

Related

Stop arbitrary function execution

For the purposes of this question, assume that I need to run some function on some object and that function will take a long time to execute (minutes). Also assume that I have no control over this function (*). How do I now cancel this function's execution?
I want to run it in a background thread to keep the main thread free and I could do that with GCD, NSOperation or NSThread. However, as far as I know, none of these support forced stopping. They can all be cancelled, but this cancellation must be implemented in the function itself - but I don't have access to that function, so I can't do that. The closest I got was using NSThread and exit(), but unfortunately it can't be applied to a instance variable (see the code example). My current plan is to try to send a notification and observe that within the object/function and kill the thread from within using Thread.exit(). I'm justing wondering if there is a "cleaner" or easier way, either built-in or 3rd party.
let someObject = Object()
// Using GCD
dispatchQueue.async { someObject.expensiveFunction() }
// Using NSOperation
operationQueue.addOperation { someObject.expensiveFunction() }
// Using NSThread
let thread = Thread { someObject.expensiveFunction() }
thread.exit() // exit is not available on an instance
(*) In this case I do have control over the function and could implement an actual cancellation, but due to the libraries I'm using, this would require a lot of refactoring.

iOS: Handling OpenGL code running on background threads during App Transition

I am working on an iOS application that, say on a button click, launches several threads, each executing a piece of Open GL code. These threads either have a different EAGLContext set on them, or if they use same EAGLContext, then they are synchronised (i.e. 2 threads don't set same EAGLContext in parallel).
Now suppose the app goes into background. As per Apple's documentation, we should stop all the OpenGL calls in applicationWillResignActive: callback so that by the time applicationDidEnterBackground: is called, no further GL calls are made.
I am using dispatch_queues to create background threads. For e.g.:
__block Byte* renderedData; // some memory already allocated
dispatch_sync(glProcessingQueue, ^{
[EAGLContext setCurrentContext:_eaglContext];
glViewPort(...)
glBindFramebuffer(...)
glClear(...)
glDrawArrays(...)
glReadPixels(...) // read in renderedData
}
use renderedData for something else
My question is - how to handle applicationWillResignActive: so that any such background GL calls can be not just stopped, but also be able to resume on applicationDidBecomeActive:? Should I wait for currently running blocks to finish before returning from applicationWillResignActive:? Or should I just suspend glProcessingQueue and return?
I have also read that similar is the case when app is interrupted in other ways, like displaying an alert, a phone call, etc.
I can have multiple such threads at any point of time, invoked by possibly multiple ViewControllers, so I am looking for some scalable solution or design pattern.
The way I see it you need to either pause a thread or kill it.
If you kill it you need to ensure all resources are released which means again calling openGL most likely. In this case it might actually be better to simply wait for the block to finish execution. This means the block must not take too long to finish which is impossible to guarantee and since you have multiple contexts and threads this may realistically present an issue.
So pausing seems better. I am not sure if there is a direct API to pause a thread but you can make it wait. Maybe a s system similar to this one can help.
The linked example seems to handle exactly what you would want; it already checks the current thread and locks that one. I guess you could pack that into some tool as a static method or a C function and wherever you are confident you can pause the thread you would simply do something like:
dispatch_sync(glProcessingQueue, ^{
[EAGLContext setCurrentContext:_eaglContext];
[ThreadManager pauseCurrentThreadIfNeeded];
glViewPort(...)
glBindFramebuffer(...)
[ThreadManager pauseCurrentThreadIfNeeded];
glClear(...)
glDrawArrays(...)
glReadPixels(...) // read in renderedData
[ThreadManager pauseCurrentThreadIfNeeded];
}
You might still have an issue with main thread if it is used. You might want to skip pause on that one otherwise your system may simply never wake up again (not sure though, try it).
So now you are look at interface of your ThreadManager to be something like:
+ (void)pause {
__threadsPaused = YES;
}
+ (void)resume {
__threadsPaused = NO;
}
+ (void)pauseCurrentThreadIfNeeded {
if(__threadsPaused) {
// TODO: insert code for locking until __threadsPaused becomes false
}
}
Let us know what you find out.

Does #synchronized guarantees for thread safety or not?

With reference to this answer, I am wondering is this correct?
#synchronized does not make any code "thread-safe"
As I tried to find any documentation or link to support this statement, for no success.
Any comments and/or answers will be appreciated on this.
For better thread safety we can go for other tools, this is known to me.
#synchronized does make code thread safe if it is used properly.
For example:
Lets say I have a class that accesses a non thread safe database. I don't want to read and write to the database at the same time as this will likely result in a crash.
So lets say I have two methods. storeData: and readData on a singleton class called LocalStore.
- (void)storeData:(NSData *)data
{
[self writeDataToDisk:data];
}
- (NSData *)readData
{
return [self readDataFromDisk];
}
Now If I were to dispatch each of these methods onto their own thread like so:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[[LocalStore sharedStore] storeData:data];
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[[LocalStore sharedStore] readData];
});
Chances are we would get a crash. However if we change our storeData and readData methods to use #synchronized
- (void)storeData:(NSData *)data
{
#synchronized(self) {
[self writeDataToDisk:data];
}
}
- (NSData *)readData
{
#synchronized(self) {
return [self readDataFromDisk];
}
}
Now this code would be thread safe. It is important to note that if I remove one of the #synchronized statements however the code would no longer be thread safe. Or if I were to synchronize different objects instead of self.
#synchronized creates a mutex lock on the object you are syncrhonizing. So in other words if any code wants to access code in a #synchronized(self) { } block it will have to get in line behind all previous code running within in that same block.
If we were to create different localStore objects, the #synchronized(self) would only lock down each object individually. Does that make sense?
Think of it like this. You have a whole bunch of people waiting in separate lines, each line is numbered 1-10. You can choose what line you want each person to wait in (by synchronizing on a per line basis), or if you don't use #synchronized you can jump straight to the front and skip all the lines. A person in line 1 doesn't have to wait for a person in line 2 to finish, but the person in line 1 does have to wait for everyone in front of them in their line to finish.
I think the essence of the question is:
is the proper use of synchronize able to solve any thread-safe
problem?
Technically yes, but in practice it's advisable to learn and use other tools.
I'll answer without assuming previous knowledge.
Correct code is code that conforms to its specification. A good specification defines
invariants constraining the state,
preconditions and postconditions describing the effects of the operations.
Thread-safe code is code that remains correct when executed by multiple threads. Thus,
No sequence of operations can violate the specification.1
Invariants and conditions will hold during multithread execution without requiring additional synchronization by the client2.
The high level takeaway point is: thread-safe requires that the specification holds true during multithread execution. To actually code this, we have to do just one thing: regulate the access to mutable shared state3. And there are three ways to do it:
Prevent the access.
Make the state immutable.
Synchronize the access.
The first two are simple. The third one requires preventing the following thread-safety problems:
liveness
deadlock: two threads block permanently waiting for each other to release a needed resource.
livelock: a thread is busy working but it's unable to make any progress.
starvation: a thread is perpetually denied access to resources it needs in order to make progress.
safe publication: both the reference and the state of the published object must be made visible to other threads at the same time.
race conditions A race condition is a defect where the output is dependent on the timing of uncontrollable events. In other words, a race condition happens when getting the right answer relies on lucky timing. Any compound operation can suffer a race condition, example: “check-then-act”, “put-if-absent”. An example problem would be if (counter) counter--;, and one of several solutions would be #synchronize(self){ if (counter) counter--;}.
To solve these problems we use tools like #synchronize, volatile, memory barriers, atomic operations, specific locks, queues, and synchronizers (semaphores, barriers).
And going back to the question:
is the proper use of #synchronize able to solve any thread-safe
problem?
Technically yes, because any tool mentioned above can be emulated with #synchronize. But it would result in poor performance and increase the chance of liveness related problems. Instead, you need to use the appropriate tool for each situation. Example:
counter++; // wrong, compound operation (fetch,++,set)
#synchronize(self){ counter++; } // correct but slow, thread contention
OSAtomicIncrement32(&count); // correct and fast, lockless atomic hw op
In the case of the linked question you could indeed use #synchronize, or a GCD read-write lock, or create a collection with lock stripping, or whatever the situation calls for. The right answer depend on the usage pattern. Any way you do it, you should document in your class what thread-safe guarantees are you offering.
1 That is, see the object on an invalid state or violate the pre/post conditions.
2 For example, if thread A iterates a collection X, and thread B removes an element, execution crashes. This is non thread-safe because the client will have to synchronize on the intrinsic lock of X (synchronize(X)) to have exclusive access. However, if the iterator returns a copy of the collection, the collection becomes thread-safe.
3 Immutable shared state, or mutable non shared objects are always thread-safe.
Generally, #synchronized guarantees thread safety, but only when used correctly. It is also safe to acquire the lock recursively, albeit with limitations I detail in my answer here.
There are several common ways to use #synchronized wrong. These are the most common:
Using #synchronized to ensure atomic object creation.
- (NSObject *)foo {
#synchronized(_foo) {
if (!_foo) {
_foo = [[NSObject alloc] init];
}
return _foo;
}
}
Because _foo will be nil when the lock is first acquired, no locking will occur and multiple threads can potentially create their own _foo before the first completes.
Using #synchronized to lock on a new object each time.
- (void)foo {
#synchronized([[NSObject alloc] init]) {
[self bar];
}
}
I've seen this code quite a bit, as well as the C# equivalent lock(new object()) {..}. Since it attempts to lock on a new object each time, it will always be allowed into the critical section of code. This is not some kind of code magic. It does absolutely nothing to ensure thread safety.
Lastly, locking on self.
- (void)foo {
#synchronized(self) {
[self bar];
}
}
While not by itself a problem, if your code uses any external code or is itself a library, it can be an issue. While internally the object is known as self, it externally has a variable name. If the external code calls #synchronized(_yourObject) {...} and you call #synchronized(self) {...}, you may find yourself in deadlock. It is best to create an internal object to lock upon that is not exposed outside of your object. Adding _lockObject = [[NSObject alloc] init]; inside your init function is cheap, easy, and safe.
EDIT:
I still get asked questions about this post, so here is an example of why it is a bad idea to use #synchronized(self) in practice.
#interface Foo : NSObject
- (void)doSomething;
#end
#implementation Foo
- (void)doSomething {
sleep(1);
#synchronized(self) {
NSLog(#"Critical Section.");
}
}
// Elsewhere in your code
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
Foo *foo = [[Foo alloc] init];
NSObject *lock = [[NSObject alloc] init];
dispatch_async(queue, ^{
for (int i=0; i<100; i++) {
#synchronized(lock) {
[foo doSomething];
}
NSLog(#"Background pass %d complete.", i);
}
});
for (int i=0; i<100; i++) {
#synchronized(foo) {
#synchronized(lock) {
[foo doSomething];
}
}
NSLog(#"Foreground pass %d complete.", i);
}
It should be obvious to see why this happens. Locking on foo and lock are called in different orders on the foreground VS background threads. It's easy to say that this is bad practice, but if Foo is a library, the user is unlikely to know that the code contains a lock.
#synchronized alone doesn't make code thread safe but it is one of the tools used in writing thread safe code.
With multi-threaded programs, it's often the case of a complex structure that you want to be maintained in a consistent state and you want only one thread to have access at a time. The common pattern is to use a mutex to protect a critical section of code where the structure is accessed and/or modified.
#synchronized is thread safe mechanism. Piece of code written inside this function becomes the part of critical section, to which only one thread can execute at a time.
#synchronize applies the lock implicitly whereas NSLock applies it explicitly.
It only assures the thread safety, not guarantees that. What I mean is you hire an expert driver for you car, still it doesn't guarantees car wont meet an accident. However probability remains the slightest.
It's companion in GCD(grand central dispatch) is dispatch_once. dispatch_once does the same work as to #synchronized.
The #synchronized directive is a convenient way to create mutex locks on the fly in Objective-C code.
side-effects of mutex locks:
deadlocks
starvation
Thread safety will depend on usage of #synchronized block.

NSOperation deadlocks and blocks NSOperationQueue

I use a subclass of NSOperation to upload large files to AWS S3 using Amazon's iOS SDK (v1.3.2). This all works fine, but some beta testers experience deadlocks (iOS 5.1.1). The result is that the NSOperationQueue in which the operations are scheduled is blocked as only one operation is allowed to run at one time. The problem is that I cannot reproduce the issue whereas the beta testers experience this problem every single time.
The operation is quite complex due to how the AWS iOS SDK works. However, the problem is not related to the AWS iOS SDK as far as I know based on my testing. The operation's main method is pasted below. The idea of the operation's main method is based on this Stack Overflow question.
- (void)main {
// Operation Should Terminate
_operationShouldTerminate = NO;
// Notify Delegate
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate operation:self isPreparingUploadWithUuid:self.uuid];
});
// Increment Network Activity Count
[self incrementNetworkActivityCount];
// Verify S3 Credentials
[self verifyS3Credentials];
while (!_operationShouldTerminate) {
if ([self isCancelled]) {
_operationShouldTerminate = YES;
} else {
// Create Run Loop
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
}
// Decrement Network Activity Count
[self decrementNetworkActivityCount];
NSLog(#"Operation Will Terminate");
}
The method that finalizes the multipart upload sets the boolean _operationShouldTerminate to YES to terminate the operation. That method looks like this.
- (void)finalizeMultipartUpload {
// Notify Delegate
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate operation:self didFinishUploadingUploadWithUuid:self.uuid];
});
// Operation Should Terminate
_operationShouldTerminate = YES;
NSLog(#"Finalize Multipart Upload");
}
The final log statement is printed to the console, but the while loop in the main method does not seem to exit as the final log statement in the operation's main method is not printed to the console. As a result, the operation queue in which the operation is scheduled, is blocked and any scheduled operations are not executed as a result.
The operation's isFinished method simply returns _operationShouldTerminate as seen below.
- (BOOL)isFinished {
return _operationShouldTerminate;
}
It is odd that the while loop is not exited and it is even more odd that it does not happen on any of my own test devices (iPhone 3GS, iPad 1, and iPad 3). Any help or pointers are much appreciated.
The solution to the problem is both complex and simple as it turns out. What I wrongly assumed was that the methods and delegate callbacks of the operation were executed on the same thread, that is, the thread on which the operation's main method was called. This is not always the case.
Even though this was true in my test and on my devices (iPhone 3GS), which is why I did not experience the problem myself. My beta testers, however, used devices with multicore processors (iPhone 4/4S), which caused some of the code to be executed on a thread different from the thread on which the operation's main method was invoked.
The result of this is that _operationShouldTerminate was modified in the finalizeMultipartUpload method on the wrong thread. This in turn means that the while loop of the main method was not exited properly resulting in the operation deadlocking.
In short, the solution is to update _operationShouldTerminate on the same thread as the main method was invoked on. This will properly exit the while loop and exit the operation.
There are a number of problems with your code, and I can offer two solutions:
1) read up on Concurrent NSOperations in Apple's Concurrency Programming Guide. To keep the runLoop "alive" you have to add either a port or schedule a timer. The main loop should contain a autorelease pool as you may not get one (see Memory Management in that same memo). You need to implement KVO to let the operationQueue know when your operation is finished.
2) Or, you can adopt a small amount of field tested hardened code and reuse it. That Xcode project contains three classes of interest to you: a ConcurrentOperation file that does well what you are trying to accomplish above. The Webfetcher.m class shows how to subclass the concurrent operation to perform an asynchronous URL fetch from the web. And the OperationsRunner is a small helper file you can add to any kind of class to manage the operations queue (run, cancel, query, etc). All of the above are less than 100 lines of code, and provide a base for you to get your code working. The OperationsRunner.h file provide a "how to do" too.

Do NSOperations and their completionBlocks run concurrently?

I've got a bunch of NSOperations added to a NSOperationQueue. The operation queue has the maxConcurrentOperationCount set to 1, so that the NSOperations run one after the other.
Now, in the completionBlock of a NSOperation I want to cancel all pending NSOperations by calling cancelAllOperations on the NSOperationQueue.
Is it safe to do this? Can I be sure that the start-method of the next operation is called only after the completionBlock of the previous operation has been fully executed? Or do the completionBlock of the previous operation and the task of the current operation run concurrently?
The reason why I'm asking: I use AFNetworking to execute a batch of AFHTTPRequestOperations and want to perform one request only if all previous requests of the batch were successful.
My findings below no longer seem to be true. I've re-run the tests on iOS 8 and iOS 9 and the completion block of an operation always runs concurrently with the next operation. Currently, I don't see a way to make an operation wait for the previous completion block to finish.
I just tried this scenario in a sample project. Here is the result:
If the NSOperationQueue's maxConcurrentOperationCount is set to 1, an NSOperation's completionBlock and the next NSOperation in the queue run simultaneously.
But, if every NSOperation is linked to its previous operation by calling addDependency:, the execution of an operation waits until the previous operation's completionBlock has finished.
So, if you want to cancel the next operation in the completionBlock of the current operation and be sure that it is cancelled before it is started, you have to set dependencies between the NSOperations by calling addDependency:
NSOperation establishes dependency only based on the completion states of operations, and not on the results of completed operations.
However, most of the scenarios that I encounter are such that, the execution of operations depend not only on the completion of some other operations, but also based on the results obtained from the completed operations.
I ended up doing like the below method, but still exploring if there is a better way:
1) Operation-A runs
2) Operation-A compeletes and its completionBlock runs
3) In the OperationA's completion block, check for the result obtained from Operation-A.
If result is X, create Operation-B and add to the queue.
If result is Y, create Operation-C and add to the queue.
If result is error, create Operation-D (usually an alert operation) and add to the queue
So, this ends up as a sequence of operations, that are dynamically added to the queue, depending on the result of completed operations.
I came up with another seemingly better way to ensure that an operaion is executed only if certain conditions (based on the results of previously finished operations) are met, else, the operation is cancelled.
One important consideration here is that the condition check for running an operation should not be coded inside the operation subclass, thus allowing the operation subclass to be poratble across different scenarios and apps.
Solution:
- Have a condition block property inside the subclass, and set whatever condition form where the operation is instantiated.
- Override "isReady" getter of the NSOperation subclass, check the condition there, and thus determine if its ready for execution.
- If [super isReady] is YES, which means the dependent operations are all finished, then evaluate the necessary condition.
- If the condition check is passed, return YES. Else, set isCancelled to YES and return YES for isReady
Code:
In the interface file have the block property:
typedef BOOL(^ConditionBlock)(void);
#property (copy) ConditionBlock conditionBlock;
In the implementation, override isReady, and cancelled:
#implementation ConditionalOperation
- (BOOL)isReady {
if([super isReady]) {
if(self.conditionBlock) {
if(!self.conditionBlock()) {
[self setCancelled:YES];
}
return YES;
} else {
return YES;
}
} else {
return NO;
}
}

Resources