我正在努力修复
Socket Rocket的竞争条件.
很久以前就报告过这个bug,但仍然没有修复.
一年多以前,我写了一个修复程序,它打破了API(只能使用共享线程),这个代码在生产中成功运行(当有很多用户时根本没有崩溃).
现在我想以这样的方式调整我的修复,它不会破坏SRWebSocket的API.
为此,我需要找到匹配的NSThread原谅NSRunLoop.这是一对一的关系,但我找到一个可以帮助我的API有问题.
PS.修复非常简单.在NSRunLoop上进行的每个操作都必须从相应的线程完成.没有可以从另一个线程安全使用的NSRunLoop或CFRunLoopAPI.所以我添加了这样的API toSRRunLoopThread`:
- (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:是线程安全的
You can use this method to deliver messages to other threads in your application.
我必须再次强调,documentation warns clearly NSRunLoop API没有线程安全:
Warning
The NSRunLoop class is generally not considered to be thread-safe and
its methods should only be called within the context of the current
thread. You should never try to call the methods of a NSRunLoop
object running in a different thread, as doing so might cause
unexpected results.
由于CFRunLoop与NSRunLoop的桥接无关,因此它具有完全相同的弱点.
因此,如果文档没有说它是线程安全的API,那么它没有线程安全,我不能在该上下文中使用它(所以@DisableR提出的答案显然是无效的).
最佳答案 您可以执行具有runloop的块而无需线程.
块将在与运行循环相关联的线程上异步执行.
CFRunLoopPerformBlock([myNSRunLoop getCFRunLoop], kCFRunLoopCommonModes, block);
CFRunLoopWakeUp([myNSRunLoop getCFRunLoop]);
下面是关于-performSelectorOnMainThread的实现的讨论:在macOS Tiger上的NSThread方法,它不可用,问题与你的非常相似:
http://www.cocoabuilder.com/archive/cocoa/112261-cfrunlooptimer-firing-delay.html