在 dispatch_release(无 ARC 情况)之后的块中调用 dispatch_semaphore_signal 是否有任何问题?

Is there any issue to call dispatch_semaphore_signal in the block after dispatch_release(no ARC case)?

  1. 以下代码在超时时是否有问题(无 ARC 情况)?

  2. 在dispatch_release(信号量)之后调用dispatch_semaphore_signal怎么样?我知道一旦所有对它的引用都被释放(引用计数变为零),一个调度对象就会被异步释放,所以在下面的代码中信号量的引用不是0?

  3. 信号量需要加__block吗?

         dispatch_time_t timeout = DISPATCH_TIME_FOREVER;
         if (waitTime > 0)
         {            
             timeout = dispatch_time(DISPATCH_TIME_NOW, waitTime * NSEC_PER_SEC);
         }
         dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);  
         dispatch_barrier_async(_dispatchQueue, ^{
             dispatch_semaphore_signal(semaphore);
         });
    
         dispatch_semaphore_wait(semaphore, timeout);
         dispatch_release(semaphore);
    

非常感谢!

基于评论。

我想你需要这样的东西。 done 变量需要同步/原子,并且代码中有两个地方需要在某个公共锁上同步。事实上,由于您只访问这些片段中的 done,因此不需要同步。

done = NO

dispatch_barrier ...
   stuff
   sync {
     if(!done)
       signal
       done = YES;
   }

wait with timeout
cancel block
sync {
  if( ! done )
    signal
    done = YES
}

// You can even test the logic as below
if DEBUG
{
  assert done == YES
}

release

我不确定取消块在非 ARC 环境中会产生什么影响,但我认为它会很好。

这将平衡信号和等待,并使释放起作用,同时防止您发出已释放信号量的信号。

这是Objective-C

中的大纲实现
    __block BOOL done = NO;
    NSObject * lock = NSObject.new;
    dispatch_semaphore_t s = dispatch_semaphore_create ( 0 );
    dispatch_queue_t queue = dispatch_queue_create( "bak",
                               dispatch_queue_attr_make_with_qos_class( DISPATCH_QUEUE_CONCURRENT,
                                                   QOS_CLASS_DEFAULT,
                                                   DISPATCH_QUEUE_PRIORITY_DEFAULT ) );

    dispatch_block_t block = dispatch_block_create ( DISPATCH_BLOCK_BARRIER, ^ {

        // Change this time to determine which one fires first
        [NSThread sleepForTimeInterval:1];

        @synchronized ( lock ) {

            if ( ! done )
            {
                done = YES;
                dispatch_semaphore_signal ( s );
                NSLog ( @"Inside fired" );
            }

        }

    } );

    // Start the block
    dispatch_async ( queue, block );

    // ... or change time here to determine which one fires first
    dispatch_semaphore_wait ( s, dispatch_time ( DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC ) );

    @synchronized ( lock ) {

        if ( ! done )
        {
            done = YES;
            dispatch_semaphore_signal ( s );
            NSLog ( @"Outside fired" );
        }

    }

    // Done, release stuff *only* if not ARC
    dispatch_release ( s );
    dispatch_release ( queue );
    dispatch_release ( block );
    lock.release;