I\'m having a hard time finding good examples on how to use these functions.
static void * kQueue1Key = \"key1\";
static void * kQueue2Key = \"key2\";
disp
As mentioned in my comment, recursive locking using dispatch_sync is, in the general case, not possible due to the possibility of non-default queue targeting. For what it's worth, given/assuming default queue targeting, here is one possible approach:
#import
#import
static dispatch_once_t recursiveLockWithDispatchQueueTLSKeyOnceToken;
static pthread_key_t recursiveLockWithDispatchQueueTLSKey;
typedef std::unordered_multiset RecursiveLockQueueBag;
static void freeRecursiveLockWithDispatchQueueTLSValue(void* tlsValue)
{
RecursiveLockQueueBag* ms = reinterpret_cast(tlsValue);
if (ms) delete ms;
}
static inline BOOL queueStackCheck(dispatch_queue_t q, BOOL checkAndPushNotPop) // If yes, check and push if not on. If no, pop.
{
dispatch_once(&recursiveLockWithDispatchQueueTLSKeyOnceToken, ^{
pthread_key_create(&recursiveLockWithDispatchQueueTLSKey, freeRecursiveLockWithDispatchQueueTLSValue);
});
RecursiveLockQueueBag* ms = reinterpret_cast(pthread_getspecific(recursiveLockWithDispatchQueueTLSKey));
if (!ms)
{
ms = new RecursiveLockQueueBag();
pthread_setspecific(recursiveLockWithDispatchQueueTLSKey, reinterpret_cast(ms));
}
const void* const vpq = reinterpret_cast((__bridge const void*)q);
BOOL alreadyOn = NO;
if (checkAndPushNotPop)
{
alreadyOn = (ms->count(vpq) > 0);
if (!alreadyOn)
{
ms->insert(vpq);
}
}
else
{
ms->erase(vpq);
}
return alreadyOn;
}
void dispatch_recursive_sync(dispatch_queue_t queue, dispatch_block_t block)
{
if (queueStackCheck(queue, YES))
{
block();
}
else
{
@try
{
dispatch_sync(queue, block);
}
@finally
{
queueStackCheck(queue, NO);
}
}
}
@implementation MyAppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
dispatch_queue_t a = dispatch_queue_create("a", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t b = dispatch_queue_create("b", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t c = dispatch_queue_create("c", DISPATCH_QUEUE_SERIAL);
//dispatch_set_target_queue(a, c);
dispatch_recursive_sync(a, ^{
dispatch_recursive_sync(b, ^{
dispatch_recursive_sync(c, ^{
dispatch_recursive_sync(a, ^{
dispatch_recursive_sync(b, ^{
dispatch_recursive_sync(c, ^{
dispatch_recursive_sync(a, ^{
NSLog(@"got there");
});
});
});
});
});
});
});
}
@end
This is the lowest-overhead implementation I could think of in a few minutes. I used C++ to avoid message sending overhead. It requires that all uses of the queue use this function. This can be useful when there's a private queue protecting internal state of an object (i.e. where the queue is private and therefore guaranteed not to be retargeted, and where you can easily ensure that all consumers of the queue use dispatch_recursive_sync.