NSCondtion with multiple threads

152 Views Asked by At

method1:

 - (void) method1
 {
    [_condition lock];

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_MSEC)), dispatch_get_main_queue(), ^{
         //Fetach data from remote, when finished call method2
         [self fetchData]; 
    });

    [_condition waitUntilDate:[NSDate dateWithTimeIntervalSinceNow:30.0]];

    // Do something.
    [_condition unlock];
}

method2:

- (void) method2
 {
    [_condition lock];
    [_condition signal];
    [_condition unlock];
}

If Thread 1 is in method1, by executing [_condition waitUtilDate ...]; it unlocks its lock. Thread 2 entered this area and also wait on the condition by executing [_condition waitUtilDate ...].

Both Thread 1 and Thread 2 enqueued a Block(request 1 request 2) to fetch the same data from remote. When request 1 finishes, it calls method2 to signal _condition:

My questions are:

  • Which will be signaled, Thread 1 or Thread 2 ?
  • 'cause request 1 and request 2 are doing the same thing, I can signal both threads(broadcast) and cancel request 2 when request 1 finishes. But, a better way is to refuse Thread 2 to enter the critical area, after request 1 is sent out. But I coundn't lock twice before entering the critical area. So what can I do?

Thanks.

1

There are 1 best solutions below

0
On BEST ANSWER

If you're trying to prevent duplicate requests you can do this with a boolean flag that you set when starting the request and then clear when you're done. You'd protect your critical regions with a mutex/semaphore/NSLock/etc.

[_lock lock];
if (_fetching) {
   [_lock unlock];
   return;
}

_fetching = YES;

[self startRequestWithCompletion: ^{ 
   [_lock lock];
   _fetching = NO;
   [_lock unlock]; 
}];

[_lock unlock];

Or you can use an NSOperationQueue and NSOperation to handle this more elegantly. You'd test the queue to see if there are any pending or running operations before starting a new one.

if (_operationQueue.operationCount)
    return;

[_operationQueue addOperationWithBlock: ^{
    // get your data
}];

How you do this really depends on exactly what you're fetching and whether the response may change based on input data. For example, I use NSOperations extensively to manage background computations. However, user input could change the result of those computations and invalidate any previous work. I hang on to a reference the NSOperation itself so I can cancel it and restart a new one where appropriate.