• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: Ordering of Completion Handlers
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Ordering of Completion Handlers


  • Subject: Re: Ordering of Completion Handlers
  • From: Andreas Grosam <email@hidden>
  • Date: Sat, 01 Sep 2012 18:53:02 +0200

On 31.08.2012, at 19:35, Seth Willits wrote:

Thank you very much Seth. It's a feasible approach.
Your idea inspired me to a simple solution which is demonstrated in the running example below.

There is only one caveat: each pending completion handler occupies a thread.


#include <Foundation/Foundation.h>
#include <dispatch/dispatch.h>
#include <stdio.h>

typedef void(^work_t)(void);
typedef void(^completion_t)(void);

static void start(work_t work, dispatch_queue_t workerQueue, completion_t completion, dispatch_queue_t completionQueue) {
    dispatch_semaphore_t sem = dispatch_semaphore_create(0);
    dispatch_async(completionQueue, ^{
        dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
        dispatch_release(sem);
        completion();
    });
    dispatch_async(workerQueue, ^{
        work();
        dispatch_semaphore_signal(sem);
    });
}

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        dispatch_semaphore_t finished = dispatch_semaphore_create(0);
        dispatch_queue_t workerQueue = dispatch_get_global_queue(0, 0);
        dispatch_queue_t completionQueue = dispatch_queue_create("serialqueue", NULL);

        start(^{printf("A"); sleep(4);}, workerQueue, ^{printf("a");}, completionQueue);
        start(^{printf("B"); sleep(3);}, workerQueue, ^{printf("b");}, completionQueue);
        start(^{printf("C"); sleep(2);}, workerQueue, ^{printf("c");}, completionQueue);
        start(^{printf("D"); sleep(1);}, workerQueue, ^{printf("d");}, completionQueue);
        start(^{printf("\n"); }, workerQueue, ^{ printf("\nfinished"), dispatch_semaphore_signal(finished);}, completionQueue);

        dispatch_semaphore_wait(finished, DISPATCH_TIME_FOREVER);
    }
    return 0;
}



> On Aug 31, 2012, at 1:08 AM, Andreas Grosam wrote:
>
>> I have a number of operations that will be received serially. Each operation can be processed concurrently with respect to each other. I would like to invoke the completion blocks for each operation in the order as they have been received.
>
>
>
> If you have operations A, B, C, D where which should execute concurrently, but their results used serially then:
>
>
> dispatch_queue_t serialQueue = …;
> dispatch_queue_t concurrentQueue = (global queue, or a new concurrent queue);
>
>
>
>
> dispatch_semaphore_t semaphoreA = dispatch_semaphore_create(0);
> __block id resultsOfA = nil;
>
>
> wrapA = ^{
> 	resultsOfA = runA();
> 	dispatch_semaphore_signal(semaphoreA);
> }
>
>
> doneA =^{
> 	dispatch_semaphore_wait(semaphoreA);
> 	completionHandlerForA(resultsOfA);
> }
>
>
>
>
> // the completion handlers are pushed onto a serial queue
> // but will not execute until the semaphore is signaled
> // after the work is done
> dipatch_async(doneA, searialQueue);
> dipatch_async(doneB, searialQueue);
> dipatch_async(doneC, searialQueue);
> dipatch_async(doneD, searialQueue);
>
> // The work fires off concurrently
> dispatch_async(wrapA, concurrentQueue);
> dispatch_async(wrapB, concurrentQueue);
> dispatch_async(wrapC, concurrentQueue);
> dispatch_async(wrapD, concurrentQueue);
>
>
>
>
>> I'm searching a simple approach to achieve this, implemented using NSOperationQueue, NSOperation and dispatch lib.
>
>
> You can do the above with NSOperationQueue using a serial queue and concurrent queue, but you must use dependencies between the operations to enforce the serial execution of the completion handlers. The standard behavior of a serial NSOpQ is that only one thing may be executed at a time, but it *does not care which order they were submitted in*. It's first *ready* first out, not first in first out. So although you may have a dependency that the completion handler operation come after the work operation, if B finishes before A, B's completion handler will run first. To stop that you need to have a dependency that A complete before B. The trouble with this is that it ends up with a chain of retains through the dependencies properties (dependencies aren't dropped from the operation even if they're met), so you need to manually remove it from within the operation itself. It's messy.
>
>
>
>
> --
> Seth Willits
>
>
>
>
> _______________________________________________
>
> Cocoa-dev mailing list (email@hidden)
>
> Please do not post admin requests or moderator comments to the list.
> Contact the moderators at cocoa-dev-admins(at)lists.apple.com
>
> Help/Unsubscribe/Update your Subscription:
>
> This email sent to email@hidden


_______________________________________________

Cocoa-dev mailing list (email@hidden)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:

This email sent to email@hidden


  • Follow-Ups:
    • Re: Ordering of Completion Handlers
      • From: Seth Willits <email@hidden>
  • Prev by Date: Re: Passing data between view
  • Next by Date: Re: Ordering of Completion Handlers
  • Previous by thread: Re: Passing data between view
  • Next by thread: Re: Ordering of Completion Handlers
  • Index(es):
    • Date
    • Thread