BLE + Core Data 导致冻结(信号量等待陷阱)
Posted
技术标签:
【中文标题】BLE + Core Data 导致冻结(信号量等待陷阱)【英文标题】:BLE + CoreData causes freeze (semaphore_wait_trap) 【发布时间】:2015-03-06 09:48:15 【问题描述】:我正在开发一个应用程序,它将通过 CoreBluetooth (BLE) 接收数据并将其与 CoreData 一起存储。它们单独工作得很好,但不能一起工作,我认为这与线程有关。
我做什么
我使用单例来处理 CoreData 交互。单例初始化代码如下。初始化代码基本上是斯坦福课程 CS193p 的复制粘贴。
第一次访问单例是当 CoreBluetooth 从蓝牙外围设备接收到某个数据块时。请参阅下面的代码。
单例初始化
static SessionManager *sharedInstance;
+ (instancetype)sharedSessionManager
NSLog(@"Shared instance requested.");
static dispatch_once_t once;
dispatch_once(&once, ^
sharedInstance = [[self alloc] init];
);
return sharedInstance;
第一次 SessionManager 访问
-(void) peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
// First some data processing
...
[[SessionManager sharedSessionManager] addMessageToCurrentSession:message];
会发生什么
在-(instancetype) init
内部,整个应用程序在下面的行冻结(零 CPU,没有内存增加)。
当断点到达这一点时(即在它执行之前),我还添加了线程的图像。
[self.document openWithCompletionHandler:^(BOOL success)
if (success) [self documentIsReady];
if (!success) NSLog(@"Could not open document %@", [self.documentPath path]);
];
我的问题
发生了什么,我做错了什么?
【问题讨论】:
在init
中调用异步方法是个坏主意。无论如何,Singleton 是个坏主意。您应该用普通类替换会话管理器单例并使用依赖注入。然后您可以从init
中删除异步方法
感谢您的评论!我不能只是从init
移动异步吗?例如,我第一次需要访问不在init
的文档。我也从这里获得了灵感,他/她似乎也遵循了类似的方法。 themainthread.com/blog/2012/03/…
是的,你可以使用这种方法,但你应该尝试让自己摆脱单身
嗯,试过了,没用。 :/ 题外话:我知道有很多关于这个的讨论,但是你的不使用单例的论点是什么?在这种情况下,我需要从多个位置与之交互的单个实体(数据库),但我知道要小心使用它们。
您看到的问题是针对 Singletons 的经典案例 - 使用 DI,您可以轻松注入 null 或模拟 SessionManager
,以便将 BT 与数据库函数分开测试
【参考方案1】:
您的问题是您的SessionManager
单例初始化存在竞争条件-您的SessionManager
init 调用openWithCompletionHandler
异步完成,因此init
在对象实际之前返回 em> 已初始化。
我建议您从 SessionManager
实现一个委托,以便在初始化完成时回调。
【讨论】:
以上是关于BLE + Core Data 导致冻结(信号量等待陷阱)的主要内容,如果未能解决你的问题,请参考以下文章
冻结(挂起)会发生在不使用互斥锁、信号量等的线程不安全代码中吗?