我正在努力修复Socket Rocket的竞争条件。很久以前就报告过这个bug,但仍然没有修复。
一年多以前,我写了一个修复程序,它打破了API(只能使用共享线程),这个代码在生产中成功运行(当有很多用户时根本没有崩溃)。
现在我想以这样的方式调整我的修复,它不会破坏SRWebSocket
的API。为此,我需要找到匹配的NSThread
原谅NSRunLoop
。这是一对一的关系,但我找到一个可以帮助我的API有问题。
NSRunLoop
must be done from a respective thread. There is no NSRunLoop
or CFRunLoopAPI that can be safely used from another thread. So I've added such API to
SRRunLoopThread`:
- (void)scheduleBlock: (void(^)())block
{
[self performSelector: @selector(_runBlock:)
onThread: self
withObject: [block copy]
waitUntilDone: NO];
}
- (void)_runBlock: (void(^)())block
{
block();
}
并在每个在这个NSRunLoop
上完成某些事情的地方使用它。
此修复程序显示了为什么我需要找到匹配的NSThread
。
注意documentations声明performSelector:onThread:withObject:waitUntilDone:
是线程安全的
您可以使用此方法将消息传递到应用程序中的其他线程。
我必须再次强调,documentation warns clearly认为NSRunLoop
API没有线程安全:
警告
NSRunLoop类通常不被认为是线程安全的,并且只应在当前线程的上下文中调用其方法。您永远不应该尝试调用在不同线程中运行的NSRunLoop对象的方法,因为这样做可能会导致意外结果。
由于CFRunLoop
与NSRunLoop
的桥梁自由桥接是一样的,所以它具有完全相同的弱点。因此,如果文档没有说它是线程安全的API,那么它没有线程安全,我不能在该上下文中使用它(所以@DisableR提出的答案显然是无效的)。
您可以执行具有runloop的块而无需线程。块将在与运行循环相关联的线程上异步执行。
CFRunLoopPerformBlock([myNSRunLoop getCFRunLoop], kCFRunLoopCommonModes, block);
CFRunLoopWakeUp([myNSRunLoop getCFRunLoop]);
这是关于在macOS Tiger上实现-performSelectorOnMainThread:
的NSThread
方法的讨论,但是这个问题与你的问题非常相似:http://www.cocoabuilder.com/archive/cocoa/112261-cfrunlooptimer-firing-delay.html