Why can't we use a dispatch_sync on the current queue?

前端 未结 6 661
梦如初夏
梦如初夏 2020-11-28 20:51

I ran into a scenario where I had a delegate callback which could occur on either the main thread or another thread, and I wouldn\'t know which until runtime (using St

6条回答
  •  有刺的猬
    2020-11-28 20:55

    The documentation clearly states that passing the current queue will cause a deadlock.

    Now they don’t say why they designed things that way (except that it would actually take extra code to make it work), but I suspect the reason for doing things this way is because in this special case, blocks would be “jumping” the queue, i.e. in normal cases your block ends up running after all the other blocks on the queue have run but in this case it would run before.

    This problem arises when you are trying to use GCD as a mutual exclusion mechanism, and this particular case is equivalent to using a recursive mutex. I don’t want to get into the argument about whether it’s better to use GCD or a traditional mutual exclusion API such as pthreads mutexes, or even whether it’s a good idea to use recursive mutexes; I’ll let others argue about that, but there is certainly a demand for this, particularly when it’s the main queue that you’re dealing with.

    Personally, I think that dispatch_sync would be more useful if it supported this or if there was another function that provided the alternate behaviour. I would urge others that think so to file a bug report with Apple (as I have done, ID: 12668073).

    You can write your own function to do the same, but it’s a bit of a hack:

    // Like dispatch_sync but works on current queue
    static inline void dispatch_synchronized (dispatch_queue_t queue,
                                              dispatch_block_t block)
    {
      dispatch_queue_set_specific (queue, queue, (void *)1, NULL);
      if (dispatch_get_specific (queue))
        block ();
      else
        dispatch_sync (queue, block);
    }
    

    N.B. Previously, I had an example that used dispatch_get_current_queue() but that has now been deprecated.

提交回复
热议问题