如何使用dispatch_queue_set_specific()和dispatch_get_specific()

hfo*_*sli 7 grand-central-dispatch objective-c-blocks

我很难找到关于如何使用这些功能的好例子.

static void * kQueue1Key = "key1";
static void * kQueue2Key = "key2";

dispatch_queue_t queue1 = dispatch_queue_create("com.company.queue1", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t queue2 = dispatch_queue_create("com.company.queue2", DISPATCH_QUEUE_SERIAL);

dispatch_queue_set_specific(queue1, kQueue1Key, (void *)kQueue1Key, NULL);
dispatch_queue_set_specific(queue2, kQueue2Key, (void *)kQueue2Key, NULL);

dispatch_sync(queue1, ^{
    if(dispatch_get_specific(kQueue1Key))
    {
        NSLog(@"I'm expecting this line to run (A)");

        dispatch_sync(queue2, ^{

            NSLog(@"I'm expecting this line to run (B)");

            if(dispatch_get_specific(kQueue2Key))
            {
                if(dispatch_get_specific(kQueue1Key))
                {
                    NSLog(@"I'm expecting this line to run (C)");
                }
                else
                {
                    [NSException raise:NSInternalInconsistencyException format:@"Should not end up here (C)"];
                }
            }
            else
            {
                [NSException raise:NSInternalInconsistencyException format:@"Should not end up here (B)"];
            }
        });
    }
    else
    {
        [NSException raise:NSInternalInconsistencyException format:@"Should not end up here (A)"];
    }
});
Run Code Online (Sandbox Code Playgroud)

结果

I'm expecting this line to run (A)
I'm expecting this line to run (B)
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Should not end up here (C)'
Run Code Online (Sandbox Code Playgroud)

这是预期的行为吗?如果我将dispatch_sync分配到queue1,因为我不在队列中,我会死锁.我错过了什么?

ipm*_*mcc 13

哦,在这里,它突然出现在为什么你得到你正在得到的东西.注释:

dispatch_sync(queue1, ^{
Run Code Online (Sandbox Code Playgroud)

当你到达这一点时,"当前队列"是 queue1

    if(dispatch_get_specific(kQueue1Key))
Run Code Online (Sandbox Code Playgroud)

您正在向当前队列询问它所具有的值kQueue1Key,您之前设置了该值,因此它会将其返回给您.

    {
        NSLog(@"I'm expecting this line to run (A)");

        dispatch_sync(queue2, ^{
Run Code Online (Sandbox Code Playgroud)

当你到达这一点时,现在是"当前队列" queue2

            NSLog(@"I'm expecting this line to run (B)");

            if(dispatch_get_specific(kQueue2Key))
Run Code Online (Sandbox Code Playgroud)

您正在向当前队列询问它所具有的值kQueue2Key,您之前设置了该值,因此它会将其返回给您.

            {

                if(dispatch_get_specific(kQueue1Key))
Run Code Online (Sandbox Code Playgroud)

您现在要求当前队列获取其所具有的值kQueue1Key.由于当前队列是queue2,你永远不设置一个值kQueue1Keyqueue2等你回来NULL.

                {
                    NSLog(@"I'm expecting this line to run (C)");
                }
                else
                {
                    [NSException raise:NSInternalInconsistencyException format:@"Should not end up here (C)"];
                }
Run Code Online (Sandbox Code Playgroud)

这里的误解是dispatch_get_specific不遍历嵌套队列的堆栈,它遍历队列目标沿袭.举例来说,如果你没有这个相反,

static void * kQueue1Key = (void*)"key1";
static void * kQueue2Key = (void*)"key2";

dispatch_queue_t queue1 = dispatch_queue_create("com.company.queue1", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t queue2 = dispatch_queue_create("com.company.queue2", DISPATCH_QUEUE_SERIAL);

dispatch_queue_set_specific(queue1, kQueue1Key, (void *)kQueue1Key, NULL);
dispatch_queue_set_specific(queue2, kQueue2Key, (void *)kQueue2Key, NULL);

// Set Queue2 to target Queue1
dispatch_set_target_queue(queue2, queue1);

dispatch_sync(queue2, ^{

    if(dispatch_get_specific(kQueue1Key))
    {
        NSLog(@"I'm expecting this line to run (A)");
    }
    else
    {
        [NSException raise:NSInternalInconsistencyException format:@"Should not end up here (C)"];
    }

    if(dispatch_get_specific(kQueue2Key))
    {
        NSLog(@"I'm expecting this line to run (B)");
    }
    else
    {
        [NSException raise:NSInternalInconsistencyException format:@"Should not end up here (C)"];
    }
});
Run Code Online (Sandbox Code Playgroud)

...目标关系是遍历的关系,而不是堆栈关系.如果存在遍历堆栈关系的东西会很好,但我不知道任何事情(你不必自己实现).