objective-c – 为NSRunLoop找到匹配的NSThread(需要修复Socket Rocket)

我正在努力修复
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

点赞