美文网首页
如何手动唤醒RunLoop

如何手动唤醒RunLoop

作者: 幸运的小强本人 | 来源:发表于2016-06-21 14:46 被阅读333次

在iOS 中,除了source1可以自己唤醒run loop之外,其他的事件都需要用户手动唤醒run loop才可以。Run Loop 提供了专门的方法来实现这个功能。其核心部分就是调用mach_msg来向指定的端口发送消息,从而唤醒线程继续工作。

void CFRunLoopWakeUp(CFRunLoopRef rl) {
  CHECK_FOR_FORK();
  // This lock is crucial to ignorable wakeups, do not remove it.
  __CFRunLoopLock(rl);

  // 忽略唤醒的情况
  if(__CFRunLoopIsIgnoringWakeUps(rl)) { 
      __CFRunLoopUnlock(rl);
      return;
  }

#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
    kern_return_t ret;
    /**
    We un conditionally try to send the message, since we don't 
    want to lose a wakeup, but the send may fail if there is 
    already a wake up pending, since the queue length is 1.
     */
     ret = __CFSendTrivialMachMessage(rl->_wakeUpPort, 0, MACH_SEND_TIMEOUT, 0);
     if(ret != MACH_MSG_SUCCESS && ret != MACH_SEND_TIMED_OUT) {
          CRASH("*** Uable to send message to wake up port, (%d)***", ret);
      }
#elif DEPLOYMENT_TARGET_WINDOWS
    SetEvent(rl->_wakeUpPort);
#endif
   CFRunLoopUnlock(rl);
}

static uint32_t __CFSendTrivialMachMessage(mach_port_t port, uint32_t msg_id, CFOptionFlags options, uint32_t timeout) {
  kern_return_t result;
  mach_msg_header_t header;
  header.msg_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
  header.msgh_size = sizeof(mach_msg_header_t);
  header.msgh_remote_port = port;
  header.msgh_local_port = MACH_PORT_NULL;
  header.msgh_id = msg_id;

  // 向指定的端口发送消息,发送完成之后返回。如果又一个线程正
  // 在这个端口等待接收消息,当收到这个消息之后,它就会被唤醒。
  result = mach_msg(&header, MACH_SEND_MSG|options, header.msgh_size, 0, MACH_PORT_NULL, timeout, MACH_PORT_NULL);
  if(result == MACH_SEND_TIMED_OUT) {
    mach_msg_destroy(&header);
  }

  return result;
}

相关文章

网友评论

      本文标题:如何手动唤醒RunLoop

      本文链接:https://www.haomeiwen.com/subject/iydgdttx.html