设为首页 加入收藏

TOP

C语言中闭包的探究及比较(四)
2013-07-22 17:59:38 来源: 作者: 【 】 浏览:1408
Tags:言中 包的 探究 比较

 

  从输出可以看出,当要执行blk的时候,test()已经执行完毕回到main函数中,对应的函数栈也已经展开,此时栈上的变量已经不存在了,继续访问导致崩溃——这也是不用int *直接访问外部变量i的原因。

  5.1 拷贝block结构体

  上文提到block结构体__block_impl的第一个成员是isa指针,使其成为NSObject的子类,所以我们可以通过相应的内存管理机制将其拷贝到堆上:

  [cpp]

  void test()

  {

  __block int i = 1024;

  void(^blk)(void) = ^{ i = 2048; printf("%d\n", i); };

  pthread_tthread;

  intret = pthread_create(&thread, NULL, testBlock, (void*)[blk copy]);

  printf("thread returns : %d\n", ret);

  sleep(1);

  }

  void*testBlock(void*blk)

  {

  sleep(2);

  printf("testBlock : Begin to exec blk.\n");

  DemoBlock demoBlk = (DemoBlock)blk;

  demoBlk();

  [demoBlk release];

  return NULL;

  }

  再次执行,得到输出:

  [cpp]

  Before test()

  threadreturns : 0

  After test()

  testBlock : Begin to exec blk.

  2048

  可以看出,在test()函数栈展开后,demoBlk仍然可以成功执行,这是由于blk对应的block结构体__main_block_impl_0已经在堆上了。不过这还不够——

  5.2 拷贝捕获的变量(__block变量)

  在拷贝block结构体的同时,还会将捕获的__block变量,即结构体__Block_byref_i_0,复制到堆上。这个任务落在前面没有讨论的__main_block_desc_0结构体身上:

  [cpp]

  static void __main_block_copy_0(struct__main_block_impl_0*dst, struct__main_block_impl_0*src) {_Block_object_assign((void*)&dst->i, (void*)src->i, 8/*BLOCK_FIELD_IS_BYREF*/);}

  static void __main_block_dispose_0(struct__main_block_impl_0*src) {_Block_object_dispose((void*)src->i, 8/*BLOCK_FIELD_IS_BYREF*/);}

  static struct __main_block_desc_0 {

  unsignedlongreserved;

  unsignedlongBlock_size;

  void(*copy)(struct__main_block_impl_0*, struct__main_block_impl_0*);

  void(*dispose)(struct__main_block_impl_0*);

  } __main_block_desc_0_DATA = { 0, sizeof(struct__main_block_impl_0), __main_block_copy_0, __main_block_dispose_0};

  栈上的__main_block_impl_0结构体为src,堆上的__main_block_impl_0结构体为dst,当发生复制动作时,__main_block_copy_0函数会得到调用,将src的成员变量i,即__Block_byref_i_0结构体,也复制到堆上。

  5.3 __forwarding指针的作用

  当复制动作完成后,栈上和堆上都存在着__main_block_impl_0结构体。如果栈上、堆上的block结构体都对捕获的外部变量进行操作,会如何?

  下面是一段示例代码:

  [cpp]

  void test()

  {

  __block int i = 1024;

  void(^blk)(void) = ^{ i++; printf("%d\n", i); };

  pthread_tthread;

  intret = pthread_create(&thread, NULL, testBlock, (void*)[blk copy]);

  printf("thread returns : %d\n", ret);

  sleep(1);

  blk();

  }

  void *testBlock(void*blk)

  {

  sleep(2);

  printf("testBlock : Begin to exec blk.\n");

  DemoBlock demoBlk = (DemoBlock)blk;

  demoBlk();

  [demoBlk release];

  returnNULL;

  }

  在test()函数中调用pthread_create创建线程时,blk被复制了一份到堆上作为testBlock函数的参数。

  test()函数中的blk结构体位于栈中,在休眠1s后被执行,对i进行自增动作。

  testBlock函数在休眠2s后,执行位于堆上的block结构体,这里为demoBlk。

  上述代码执行后输出:

  [cpp]

  Beforetest()

  thread returns : 0

  1025

  Aftertest()

  testBlock : Begin to execblk.

  1026

  可见无论是栈上的还是堆上的block结构体,修改的都是同一个__block变量。

  这就是前面提到的__forwarding指针成员的作用了:

  起初,栈上的__block变量的成员指针__forwarding指向__block变量本身,即栈上的__Block_byref_i_0结构体。

  当__block变量被复制到堆上后,栈上的__block变量的__forwarding成员会指向堆上的那一份拷贝,从而保持一致。

              

首页 上一页 1 2 3 4 5 6 7 下一页 尾页 4/9/9
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇C语言中的序列点和副作用 下一篇C语言复杂声明的本质与局限

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: