dispatch_async复制内部块 [英] does dispatch_async copy internal blocks

查看:146
本文介绍了dispatch_async复制内部块的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给出以下(手动引用计数):

Given the following (manual reference counting):

void (^block)(void) = ^ {
    NSLog(@"wuttup");
}

void (^async_block)(void) = ^ {
    block();
}

dispatch_async(dispatch_get_main_queue(), async_block);

是否会复制阻止而不是从堆栈中抛出并销毁?

Will "block" be copied rather than thrown off the stack and destroyed?

推荐答案

我相信答案是肯定的。

I believe, the answer is Yes.

外部块将被异步调度,这会导致运行时在此块的堆上进行复制。如下所示,并在块实现规范 - Clang 3.4文档,内部块的导入变量也被复制到堆中。

The outer block will be asynchronously dispatched which causes the runtime to make a copy on the heap for this block. And as shown below, and described in the Block Implementation Specification - Clang 3.4 Documentation, the inner block's imported variables are also copied to the heap.

在OP的例子中,我们有一个块引用的导入常量副本。

In the OP's example we have a "imported const copy of a Block reference".

我正在使用规范中的示例:

I'm using the example in the Specification:

void (^existingBlock)(void) = ...;
void (^vv)(void) = ^{ existingBlock(); }
vv();

规范声明 copy_helper dispose_helper 需要函数:


copy_helper函数既传递现有的基于堆栈的指针以及指向新堆版本的指针,并应回调到运行时以实际对块内导入的字段执行复制操作。

The copy_helper function is passed both the existing stack based pointer and the pointer to the new heap version and should call back into the runtime to actually do the copy operation on the imported fields within the Block.

规范中的以下示例代码难以解密(实际上缺少描述将外部块复制到堆时会发生什么)。无论如何,看起来规范试图表明内部块的导入变量将(递归地)复制到外部块的原始存储区域中。

The following example code in the Specification is difficult to decipher (and actually lacks the description what happens when the outer block is copied to the heap). Anyway, it appears the specification tries to show that imported variables of inner blocks will be (recursively) copied into the raw storage area of the outer block.

当外部块时将被复制到堆上,似乎内部块的导入变量最终将存在于堆上。

When the outer block will be copied on the heap, it seems imported variables of inner blocks will eventually live on the heap as well.

嗯,直觉上,这一切都是有道理的。

Well, intuitively, this all makes sense.

我做了一个小测试程序,它将证明这一点:
(您必须调试并检查反汇编以了解表面下发生的事情)。

I made a small test program which will demonstrate this: (you have to debug and examine the disassembly in order to figure out whats going on under the surface).

#import <Foundation/Foundation.h>


void foo(int param)
{
    int x0 = param;
    int x1 = param + 1;
    void (^existingBlock)(void) = ^{
        int y0 = x0;
        int y1 = x1;
        printf("&y0: %p\n", &y0);
        printf("&y1: %p\n", &y1);
        printf("&x0: %p\n", &x0);
        printf("&x1: %p\n", &x1);
    };

    void (^vv)(void) = ^{
        int y2 = x0;
        int y3 = x1;
        existingBlock();
        printf("&y2: %p\n", &y2);
        printf("&y3: %p\n", &y3);
        printf("&x0: %p\n", &x0);
        printf("&x1: %p\n", &x1);
    };

    printf("Stack: &x: %p\n", &x0);
    printf("Stack: &x: %p\n", &x1);

    printf("------- on main thread -------\n");
    vv();

    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        printf("------- on thread 2 -------\n");
        assert(vv);
        sleep(1);
        int y4 = x0;
        int y5 = x1;
        vv();
        printf("&y4: %p\n", &y4);
        printf("&y5: %p\n", &y5);
        printf("&x0: %p\n", &x0);
        printf("&x1: %p\n", &x1);
    });
}

int main(int argc, const char * argv[])
{
    @autoreleasepool {

        foo(1);
        sleep(2);
    }
    return 0;
}

输出如下:

Stack: &x: 0x7fff5fbff868
Stack: &x: 0x7fff5fbff864
------- on main thread -------
&y0: 0x7fff5fbff70c
&y1: 0x7fff5fbff708
&x0: 0x1001081e0
&x1: 0x1001081e4
&y2: 0x7fff5fbff76c
&y3: 0x7fff5fbff768
&x0: 0x10010a588
&x1: 0x10010a58c
------- on thread 2 -------
&y0: 0x1000e5d9c
&y1: 0x1000e5d98
&x0: 0x1001081e0
&x1: 0x1001081e4
&y2: 0x1000e5dfc
&y3: 0x1000e5df8
&x0: 0x10010a588
&x1: 0x10010a58c
&y4: 0x1000e5e6c
&y5: 0x1000e5e68
&x0: 0x10010a5e8
&x1: 0x10010a5ec

当块在主线程上执行时,它会存在于堆栈中(如由本地和导入变量的地址显示)。当通过 dispatch_async 执行时,运行时已经复制了块 - 包括内部块,可以通过块的本地和导入变量的地址看到。

When the block is executed on the main thread, it lives on the stack (as shown by the addresses of the local and imported variables). When executed via dispatch_async the runtime has copied the block - including the inner blocks, as can be seen by the addresses of the local and imported variables of the blocks.

我们可以在 copy_helper_block 函数中设置一个断点,实际上,程序在那里停止一次,以便复制块 vv 到堆。

We can set a breakpoint at the copy_helper_block function, and in fact, the program stops there once, in order to copy the block vv to the heap.

这篇关于dispatch_async复制内部块的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆