使用信号量阻止许多,然后释放所有

时间:2014-04-30 19:26:50

标签: objective-c grand-central-dispatch semaphore

我有多个异步任务都依赖于初始异步身份验证步骤才能成功。我正在使用信号量来阻止所有安全任务,直到身份验证完成。它主要用于计时目的,因为任务依赖于在身份验证结束时获得的安全令牌。身份验证涉及网络请求,可能需要几秒钟。

我的代码中的难度似乎是认证后发出的dispatch_semaphore_signal()仅表示第一个信号量锁可能会继续。第二个将继续阻止。将来可能有许多阻塞任务,都在等待信号量。

我想知道是否有更清洁的方法来解决这个问题。我相信每个等待任务都可以立即发出另一个dispatch_semaphore_signal(),从而释放下一个任务,依此类推。有没有办法在一次通话中释放所有阻塞信号量?

使用GCD有更清洁的方法吗?我不熟悉GCD,所以代码片段在以下用法的上下文中有所帮助。

dispatch_semaphore_t sem = dispatch_semaphore_create(0);

// in actuality, these 3 may be any where in the app, in different classes, methods, etc
// so a completionHandler is not possible
[self authentication];      // async, could take many seconds
[self authenticatedTask1];  // async
[self authenticatedTask2];  // async

- (void) authentication {
  // async url request, assume it is configured here
  [NSURLConnection sendAsynchronousRequest:urlRequest queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
     // authenticate
     authenticated = TRUE;
     secure_token = @"4rjiofwefsdf"; // obtained during auth
     dispatch_semaphore_signal(sem);
   }];
}

- (void) authenticatedTask1 {
  // put on new thread, so semaphore doesn't block program
  dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
    if(!authenticated){
      // wait until authenticated
      dispatch_semaphore_wait(sem)
    }
    // continue after authenticated, using secure_token
  });
}

- (void) authenticatedTask2 {
  // put on new thread, so semaphore doesn't block program
  dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
    if(!authenticated){
      // wait until authenticated
      dispatch_semaphore_wait(sem)
    }
    // continue after authenticated, using secure_token
  });
}

3 个答案:

答案 0 :(得分:3)

您可以将经过身份验证的任务放入自己的挂起调度队列中,并在身份验证成功后恢复调度队列。

答案 1 :(得分:2)

它不是很优雅但你可以打电话给dispatch_semaphore_signal'紧跟在' dispatch_semaphore_wait'之后。它应该解决问题。

- (void)authenticatedTask1 {
  // put on new thread, so semaphore doesn't block program
  dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
    if(!authenticated){
      // wait until authenticated
      dispatch_semaphore_wait(sem);
      dispatch_semaphore_signal(sem); // !!!
    }
    // continue after authenticated, using secure_token
  });
}

答案 2 :(得分:1)

您可以传入要在块中执行的方法以在completltion块中运行,然后您就不需要使用信号量了。此外,您不必费心等待信号量完成dispatch_async

[self authenticationWithCompletionBlock:^{
    [self authenticatedTask1];
    [self authenticatedTask2];
}];

- (void) authenticationWithCompletionBlock:(dispatch_block_t)block {
  // async url request, assume it is configured here
  [NSURLConnection sendAsynchronousRequest:urlRequest queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
     // authenticate
     authenticated = TRUE;
     secure_token = @"4rjiofwefsdf"; // obtained during auth
     block();
   }];
}

如果方法属于同一个类,则可以直接调用方法而不是块。

如果您需要知道两个异步任务(在您的情况下为authenticatedTask1authenticatedTask2)何时完成,那么您需要使用dispatch groups