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 (Cocoa-dev@lists.apple.com)
> 
> 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:
> https://lists.apple.com/mailman/options/cocoa-dev/agrosam%40onlinehome.de
> 
> This email sent to agro...@onlinehome.de


_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to