ibm123
ibm123

Reputation: 1254

IOS thread pool

I've got this method

-(void)addObjectToProcess(NSObject*)object;

and i want this method to add the object to process queue which can process up to 4 objects in parallel.

i've created my own dispatch_queue and semhphore

 _concurrentQueue = dispatch_queue_create([queue_id UTF8String],DISPATCH_QUEUE_CONCURRENT);
 _processSema = dispatch_semaphore_create(4);

and the implementation of the method is:

-(void)addObjectToProcess(NSObject*)object {
    dispatch_semaphore_wait(self.processSema, DISPATCH_TIME_FOREVER);
    __weak MyViewController* weakSelf = self;

    dispatch_async(self.concurrentQueue, ^{
        // PROCESS...........
        // ..................
        dispatch_semaphore_signal(self.processSema);
        dispatch_async(dispatch_get_main_queue(), ^{
            // call delegate from UI thread
        });
    });
    }

it seems the caller sometimes gets blocked cause of the semaphore barrier.

is there any other/easier option to implement what i'm trying to make here ?

Thanks

Upvotes: 2

Views: 1512

Answers (1)

Rob
Rob

Reputation: 437552

The problem is that you're calling dispatch_semaphore_wait on whatever thread you called addObjectToProcess on (presumably the main thread). Thus, if you already have four tasks running, when you schedule this fifth process, it will wait on the main thread.

You don't, though, just want to move the waiting for the semaphore into the block dispatched to self.concurrentQueue, because while that will successfully constrain the "PROCESS" tasks to four at a time, you will consume another worker thread for each one of these backlogged dispatched tasks, and there are a finite number of those worker threads. And when you exhaust those, you could adversely affect other processes.

One way to address this would be to create a serial scheduling queue in addition to your concurrent processing queue, and then dispatch this whole scheduling task asynchronously to this scheduling queue. Thus you enjoy the maximum concurrency on the process queue, while neither blocking the main thread nor using up worker threads for backlogged tasks. For example:

@property (nonatomic, strong) dispatch_queue_t schedulingQueue;

And

self.schedulingQueue = dispatch_queue_create("com.domain.scheduler", 0);

And

- (void)addObjectToProcess(NSObject*)object {
    dispatch_async(self.schedulingQueue, ^{
        dispatch_semaphore_wait(self.processSema, DISPATCH_TIME_FOREVER);
        typeof(self) __weak weakSelf = self;

        dispatch_async(self.concurrentQueue, ^{
            // PROCESS...........
            // ..................
            typeof(self) __strong strongSelf = weakSelf;
            if (strongSelf) {
                dispatch_semaphore_signal(strongSelf.processSema);
                dispatch_async(dispatch_get_main_queue(), ^{
                    // call delegate from UI thread
                });
            }
        });
    });
} 

Another good approach (especially if the "PROCESS" is synchronous) is to use NSOperationQueue that has a maxConcurrentOperationCount, which controls the degree of concurrency for you. For example:

@property (nonatomic, strong) NSOperationQueue *processQueue;

And initialize it:

self.processQueue = [[NSOperationQueue alloc] init];
self.processQueue.maxConcurrentOperationCount = 4;

And then:

- (void)addObjectToProcess(NSObject*)object {
    [self.processQueue addOperationWithBlock:^{
        // PROCESS...........
        // ..................
        dispatch_async(dispatch_get_main_queue(), ^{
            // call delegate from UI thread
        });
    }];
}

The only trick is if the "PROCESS", itself, is asynchronous. If you do that, then you can't just use addOperationWithBlock, but rather have to write your own custom, asynchronous NSOperation subclass, and then use addOperation to the NSOperationQueue. It's not hard to write asynchronous NSOperation subclass, but there are a few little details associated with that. See Configuring Operations for Concurrent Execution in the Concurrency Programming Guide.

Upvotes: 3

Related Questions