Béatrice Cassistat
Béatrice Cassistat

Reputation: 1078

Exiting a NSThread to break out from an infinite loop without cancellation point

I am unsure if what I am trying to achieve is possible.

I got a bug while rendering PDF pages into images, it seems that our application is encountering erroneous PDF documents sometime and some rendering are taking literally forever (never exiting), causing our application to be stopped by the user. (The PDF are truly problematic, even the Apple Preview app stops responding when it shows the problematic pages.)

I tried to fix the issue by putting the pdf rendering work in a second thread, while the current thread awaits for the result and try to cancel the NSThread if the rendering timed out.

MAImageRepDrawing* imageRepDrawing = [[MAImageRepDrawing alloc] initWithImageRep:imgRep ...];
NSThread* thread = [[NSThread alloc] initWithTarget:imageRepDrawing selector:@selector(doDrawImageRep) object:nil];
[thread start];

double timeOutAt = 0;
if (IMAGE_REP_RENDERING_TIMEOUT > 0)
    timeOutAt = CFAbsoluteTimeGetCurrent() + (IMAGE_REP_RENDERING_TIMEOUT / 1000.0);
while (![imageRepDrawing isEnded]) {
    sleep(1);
    if ((IMAGE_REP_RENDERING_TIMEOUT > 0) && (CFAbsoluteTimeGetCurrent() > timeOutAt)) {
        [thread cancel];
        break;
    }
}

[thread release];
...

Unfortunately, it does not completely fix the problem, it seems that the timeout mechanism is working well and the function returns, and thus the application continue. But the NSThread does not cancel and the application gained an unuseful thread using about 100% of CPU (one core). The next time a timeout occurs, there may be two thread using about 200% of CPU (two cores). Etc. So my conclusion is that the drawing process is not looking for cancellation.

I was looking some kind of fix, even if it may be ugly, like invoking [NSThread exit], but I can't invoke this static function from the current thread... I don't see any other useful function: https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSThread_Class/

Is there anything else that could be done?

Thanks!

Upvotes: 2

Views: 299

Answers (1)

bbum
bbum

Reputation: 162712

There is no way to deterministically terminate a thread from outside of said thread as there is no way to know the target thread's state or what side effects might be incurred by terminating it.

Since this kills Apple's code, please file a bug and attach the erroneous PDF.

One viable option might be to pre-flight in an external process (which can be safely killed -- but you can't do this on iOS) and either shuttle across the rendered images or then re-render in your app, if the pre-flighting passes.

Upvotes: 4

Related Questions