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(@"********");
}