0

I have a prebuilt C library (binary file and header) with one heavy function. This function can take minute or more to complete. Usially I use GCD to move calculations in background and keep UI thread free:

// show activity indicator or something else

dispatch_queue_t queue = dispatch_queue_create(NULL, NULL);
dispatch_async(queue, ^{
    void *resultData = callOfHeavyLibraryMethodHere(params);
    dispatch_async(dispatch_get_main_queue(), ^{
        // show resultData to user
    });
});

But what if user wants to cancel this operation? As I know, I can't stop running block in GCD. I read about NSThread - but it also no way to kill one thread (with calculations) from other thread (main). Is there any other solutions?

I can't use solution from this answer How to cancel/exit/stop execution of Thread object or thread running in background in IOS because even if I call cancel method I have no place to check isCancelled variable.

this is NOT my case:

NSOperationQueue* myQueue = [[NSOperationQueue alloc] init];
NSBlockOperation* myOp = [[NSBlockOperation alloc] init];

[myOp addExecutionBlock:^{
    for (int i = 0; i < 1000000; i++)
    {
        if ([myOp isCancelled]) // <-- check and interrupt operation
            return;
        doSmallPartOfWorkForItemAtIndex(i);
    }
}];
[myQueue addOperation:myOp];

and this is my case:

NSOperationQueue* myQueue = [[NSOperationQueue alloc] init];
NSBlockOperation* myOp = [[NSBlockOperation alloc] init];

[myOp addExecutionBlock:^{
    void *resultData = callOfHeavyLibraryMethodHere(params);
    // pass data somewhere else
}];
[myQueue addOperation:myOp];

There is no way to check isCancelled and operation will not interrupt in this way. Also I can't call [NSThread exit] too, because there is no intermediate point in my code.

Stanislav Chernischuk
  • 975
  • 1
  • 11
  • 24
  • Possible duplicate of [How to cancel/exit/stop execution of Thread object or thread running in background in IOS](https://stackoverflow.com/questions/15413955/how-to-cancel-exit-stop-execution-of-thread-object-or-thread-running-in-backgrou) – Pulkit Kumar Singh Sep 20 '17 at 11:54

1 Answers1

-1

The problem with dispatch queues is that you can't cancel a task once you dispatch it. However, you can use NSOperationQueue instead

NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
    void *resultData = callOfHeavyLibraryMethodHere(params);
    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
        // Main thread work (UI usually)
    }];
}];

NSOperationQueue *queue = [NSOperationQueue new];
[queue addOperation:operation];
// you can cancel an operation like so
[operation cancel];

Ability to cancel a task is one advantage NSOperationQueue have over GCD. Another one is possibility to add dependencies between operations, to it can be really handy.

mag_zbc
  • 6,801
  • 14
  • 40
  • 62
  • 1
    Sorry, but as I understand, in that case my NSOperation (or it subclass) must support cancellation, but I can't provide small blocks and isCancelled variable observing because of my library limitations (one huge task, no parts). https://stackoverflow.com/questions/7820960/how-to-stop-current-nsoperation/7821125#7821125 – Stanislav Chernischuk Sep 20 '17 at 11:40
  • You don't need to provide small blocks or monitor anything - just put all your code in `NSBlockOperation` and add it to `NSOperationQueue`. And, if you need to cancel, just call `cancel` on your operation. – mag_zbc Sep 20 '17 at 11:45
  • But here: https://stackoverflow.com/a/13030641/7886687 I also see isCancelled property checks. Ok, I will test this solution in my case and write about results. – Stanislav Chernischuk Sep 20 '17 at 11:52
  • Yes, in the answer you quoted, there is `isCanceled` property check. Do *you* need to check it periodically? – mag_zbc Sep 20 '17 at 11:58
  • 1
    So, as I expected, "cancel" method call does nothing. Task never stop. This is because YOU must check isCancelled and interrupt your code. But this is possible only if you have chunks of data in some loop. In my code there is no loops. – Stanislav Chernischuk Sep 20 '17 at 11:58
  • @StanislavChernischuk, did you ever find a solution? – der_michael Oct 02 '17 at 18:55
  • @der_michael with threads - no, sorry. Looks like there are only two workaraunds. The first is to get library source and manually add isCancelled (or other interrupt option) in its "heavy" loops. And the second is to use NSTask and run separate process (not thread), with "interrupt" method available. But for now I don't try this and I have not complete working solution. – Stanislav Chernischuk Oct 02 '17 at 20:36