总结:
一旦在子线程调用了 [[NSRunLoop currentRunLoop] run] 方法,那么在这个方法下的代码就永远无法执行到。若要继续往下执行代码,可使用 [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:seconds]] 方法代替。
参考文献:子线程上的RunLoop运行循环
Tip: @synchronized 的底层实现是使用了 recursive_mutex_t。
- (void)startTimer {
self.timerThread = [[NSThread alloc] initWithTarget:self selector:@selector(createTimer) object:nil];
[self.timerThread start];
}
// 加锁方式:在子线程上的启用RunLoop
- (void)createTimer {
// 方法一:该方法会死锁
@synchronized (self) {
if (self.heartbeatTimer) {
[[NSRunLoop currentRunLoop] addTimer:self.heartbeatTimer forMode:NSRunLoopCommonModes];
[[NSRunLoop currentRunLoop] run];
}
}
NSRecursiveLock *recLock = [[NSRecursiveLock alloc] init];
// 方法二:该方法会死锁
[recLock lock];
if (self.heartbeatTimer) {
[[NSRunLoop currentRunLoop] addTimer:self.heartbeatTimer forMode:NSRunLoopCommonModes];
[[NSRunLoop currentRunLoop] run]; // 调用这个方法,会开启子线程的运行循环,不会停止,下面👇🏻的代码就始终执行不到了。
// [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:60]]; // 调用这个方法,会开启子线程的运行循环,不会停止,直到 60s 后退出循环,在 60s 过后,下面👇🏻的代码才会执行。
[recLock unlock];
}
// 方法三:该方法不会死锁
[recLock lock];
if (self.heartbeatTimer) {
[[NSRunLoop currentRunLoop] addTimer:self.heartbeatTimer forMode:NSRunLoopCommonModes];
[recLock unlock]; // 在 [[NSRunLoop currentRunLoop] run] 方法前解锁,避免死锁。
[[NSRunLoop currentRunLoop] run];
}
}
网友评论