关于Objective C:使用信号量阻止很多,然后释放所有

Using semaphore to block many, then release all

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

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

我想知道是否有更干净的方法来进行此阻止。我相信每个等待的任务都可以立即发出另一个dispatch_semaphore_signal(),从而释放下一个任务,依此类推。有没有一种方法可以在一个调用中释放所有阻塞信号量?

是否有使用GCD的更干净的方法?我不熟悉GCD,因此在以下用法的背景下,代码段会有所帮助。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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
  });
}

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


这不是很优雅,但是您可以在" dispatch_semaphore_wait "之后立即调用" dispatch_semaphore_waital"。它应该可以解决问题。

1
2
3
4
5
6
7
8
9
10
11
- (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
  });
}


您可以将要在块中执行的方法传递给要在completltion块中运行的方法,那么您就不需要使用信号量。同样,您也无需费心dispatch_async等待信号量完成:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[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)何时完成,则需要使用调度组。