RunLoop的核心

RunLoop的核心部分就是当有任务需要处理的时候,线程被唤醒,执行指定的任务。当没有任务需要处理的时候,线程处于休眠状态。直到有新的任务将其唤醒为止。

这里就牵涉到两个线程之间的通信问题。在iOS 中,RunLoop 使用的是mach port的通信方式。当线程没有任务需要处理的时候,它就调用mach_msg 函数,使线程处于休眠状态,同时在指定端口等待被唤醒。当另外一个线程完成了自己的任务,需要唤醒前面的线程,处理一定的操作的时候,也是调用mach_msg 函数,向线程等待消息的端口发送消息。然后,系统就会将休眠的线程唤醒,就可以执行相关的操作了。

就是这样,RunLoop实现了线程有任务的时候,处理任务,没有任务的时候处于休眠状态,不消耗任何CPU资源。避免了忙等等情况的出现。

下面简单列出两个线程之间通信的代码:

@implementation ViewController {
    mach_port_t mPort;
}

- (void)viewDidLoad {
  [super viewDidLoad];

   NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(test) object:nil];
   [thread start];


  UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
  btn.backgroundColor = [UIColor redColor];
  btn.frame = CGRectMake(100, 100, 100, 50);
  [btn addTarget:self action:@selector(btnClicked) forControlEvents:UIControlEventTouchUpInside];
  [self.view addSubview:btn];
}  

- (void)btnClicked {
  kern_return_t result;
  mach_msg_header_t header;
  header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
  header.msgh_size = sizeof(mach_msg_header_t);
  header.msgh_remote_port = mPort;
  header.msgh_local_port = MACH_PORT_NULL;
  header.msgh_id = 0;
  result = mach_msg(&header, MACH_SEND_MSG, header.msgh_size, 0, MACH_PORT_NULL, 0, MACH_PORT_NULL);

  if (result == MACH_SEND_TIMED_OUT) mach_msg_destroy(&header);
}

- (void)test {
    mach_port_t result = 0;
    kern_return_t ret = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &result);

    ret = mach_port_insert_right(mach_task_self(), result, result, MACH_MSG_TYPE_MAKE_SEND);

    mach_port_limits_t limits;
    limits.mpl_qlimit = 2;
    ret = mach_port_set_attributes(mach_task_self(), result, MACH_PORT_LIMITS_INFO, (mach_port_info_t)&limits, MACH_PORT_LIMITS_INFO_COUNT);

    if (KERN_SUCCESS != ret) {
        char msg[256];
        snprintf(msg, 256, "*** The system has no mach ports available. You may be able to diagnose which application(s) are using ports by using 'top' or Activity Monitor. (%d) ***", ret);
     }
    mPort = result;
    uint8_t msg_buffer[3 * 1024];
    mach_msg_header_t *msg = NULL;
    msg = (mach_msg_header_t *)msg_buffer;
    msg->msgh_id = 0;
    msg->msgh_bits = 0;
    msg->msgh_remote_port = MACH_PORT_NULL;
    msg->msgh_size = sizeof(mach_msg_header_t);
    msg->msgh_local_port = result;

    NSLog(@"start");
    int ret1 = mach_msg(msg, MACH_RCV_MSG | MACH_RCV_TIMEOUT, 0, msg->msgh_size, result, 1000000, MACH_PORT_NULL);
    if (ret1 == MACH_MSG_SUCCESS) {
        NSLog(@"hahahahahh");
    }
    NSLog(@"********");
}

推荐阅读更多精彩内容