【问题标题】:How to wait for completion handler inside a @synchronized block?如何在 @synchronized 块内等待完成处理程序?
【发布时间】:2017-09-26 19:57:31
【问题描述】:

我想在关键部分内同步调用完成处理程序(使用 @synchronized 块)。我正在尝试使用信号量等待完成处理程序,但从未调用信号量信号。

这是我正在做的事情:

NSNumber *lock = 0;
@synchronized(lock) {
    // critical section code begins
    dispatch_semaphore_t sema = dispatch_semaphore_create(0);
    [self someMethodWithCompletionHandler:^(BOOL result) {
        // execute completion handler
        dispatch_semaphore_signal(sema);
    }];
    // wait for completion block to finish
    dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
    // critical section code ends
}

我相信,由于 @synchronized 块,完成处理程序在与调用者相同的线程上被调用,这会导致死锁。那正确吗?如果是,还有什么方法可以实现?

谢谢!

【问题讨论】:

  • 尝试使异步事物同步通常是个坏主意。您需要确保someMethodWithCompletionHandler 既能完成工作,又会将完成处理程序分派到不同队列中,以与您使用“等待”阻塞的队列进行处理。如果您在主队列上等待,那将非常糟糕。添加同步块只会使其变得更加复杂,因为您现在有第二个潜在的保持等待死锁触发器。
  • 我不会使用@syncrhonized 块,而是将整个临界区异步调度到私有串行调度队列上,并将someMethodWithCompletionHandler 异步调度到另一个实用程序队列或主队列上。然后你的信号量可以安全地阻塞你的私有队列。
  • 但是我希望临界区代码是同步的。将整个临界区异步调度到另一个串行线程会使其异步吗?我在关键部分之后有代码,应该在关键部分完成后执行。
  • @Paulw11 我尝试使用 dispatch_sync 但它在主线程中执行!有什么想法吗?
  • 不要使用调度同步。接受它应该是异步的事实。使用 dispatch group 和 dispatch group notify 来执行临界区之后的代码。调度同步将在你调度到的任何队列上执行代码,但它仍然会阻塞当前队列等待该调度完成,如果当前队列是主队列,这很糟糕。即使您分派到另一个队列,如果该线程可用,代码也可能在主线程上执行。主队列总是使用主线程。其他队列可能使用主线程

标签: ios objective-c multithreading semaphore ios-multithreading


【解决方案1】:

我会避免使用@synchronized 并使用串行调度队列来序列化关键部分中的工作。您仍然可以使用信号量来阻塞串行调度队列,直到异步操作完成。

串行调度队列保证一次只能有一个代码块进入临界区,不存在阻塞主队列的风险。

您需要在类初始化期间创建串行队列

@property (strong,nonatomic) dispatch_queue_t serialQueue;

- (id)init {
    if (self = [super init]) {
        self.serialQueue = dispatch_queue_create("com.example.CriticalTaskQueue", NULL);
    }
    return self;
}

- submitSomeCriticalWork() {

    dispatch_async(self.serialQueue, ^{
        dispatch_semaphore_t sema = dispatch_semaphore_create(0);
        [self someMethodWithCompletionHandler:^(BOOL result) {
         // execute completion handler
            dispatch_semaphore_signal(sema);
        }];
    // wait for completion block to finish
     dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
    // critical section code ends
   }];

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-03
    • 1970-01-01
    相关资源
    最近更新 更多