objective-c - 如何在 Objective C / async 问题中解决这种竞争条件?'索引 1 超出空数组的范围'
问题描述
嗨,我有这个库的问题:LTSupportAutomotive
我是一个快速的程序员,所以在目标 c 方面不是很好。
如何解决这种竞争状况?
我希望有一个人可以帮助我。
'*** -[__NSArrayM insertObject:atIndex:]: 空数组的索引 1 超出范围'
-(void)asyncEnqueueInternalCommand:(LTOBD2AdapterInternalCommand*)internalCommand
{
@synchronized(self) {
[_commandQueue addObject:internalCommand];
}
}
源代码:
更新 1:
使用第一个修复创建了一个分支: https ://github.com/Skyb0rg/LTSupportAutomotive/tree/BugfixMemoryManagement
添加额外的 commandQueue 后,我得到了新的错误:
在 LTBTLEWriteCharacteristicStream.m
-(void)characteristicDidWriteValue
{
[self.delegate stream:self handleEvent:NSStreamEventHasSpaceAvailable];
}
此函数崩溃:在当前参数寄存器中找到选择器名称:委托
线程 6 崩溃:0 libobjc.A.dylib 0x00000001bcc19430 objc_retain + 16
1 LTSupportAutomotive 0x00000001093c2a34 -[LTBTLEWriteCharacteristicStream 特性DidWriteValue] (LTBTLEWriteCharacteristicStream.m:39)
2 LTSupportAutomotive 0x00000001093c2714 -[LTBTLESerialTransporter 外围设备:didWriteValueForCharacteristic:error:] (LTBTLESerialTransporter.m:311)
3 核心蓝牙 0x00000001c35e6ce0 -[CBPeripheral handleAttributeEvent:args:attributeSelector:delegateSelector:delegateFlag:] + 236
4 核心蓝牙 0x00000001c35e6e40 -[CBPeripheral 句柄CharacteristicEvent:characteristicSelector:delegateSelector:delegateFlag:] + 128
5 核心蓝牙 0x00000001c35e24f0 -[CBPeripheral handleMsg:args:] + 352
6 核心蓝牙 0x00000001c35dcbfc -[CBCentralManager handleMsg:args:] + 200
7 核心蓝牙 0x00000001c35eb770 __30-[CBXpcConnection _handleMsg:]_block_invoke + 56
8 libdispatch.dylib 0x00000001bd4696c8 _dispatch_call_block_and_release + 20
9 libdispatch.dylib 0x00000001bd46a484 _dispatch_client_callout + 12
10 libdispatch.dylib 0x00000001bd411bd0 _dispatch_lane_serial_drain$VARIANT$mp + 588
11 libdispatch.dylib 0x00000001bd41274c _dispatch_lane_invoke$VARIANT$mp + 480
12 libdispatch.dylib 0x00000001bd411a9c _dispatch_lane_serial_drain$VARIANT$mp + 280
13 libdispatch.dylib 0x00000001bd412718 _dispatch_lane_invoke$VARIANT$mp + 428
14 libdispatch.dylib 0x00000001bd41aeb8 _dispatch_workloop_worker_thread + 596
15 libsystem_pthread.dylib 0x00000001bd64d0dc _pthread_wqthread + 308
16 libsystem_pthread.dylib 0x00000001bd64fcec start_wqthread + 0
和另一个崩溃:LTBTLEReadCharacteristicStream.m
-(void)characteristicDidUpdateValue
{
NSData* value = _characteristic.value;
[_buffer appendData:value];
[self.delegate stream:self handleEvent:NSStreamEventHasBytesAvailable];
}
*** 由于未捕获的异常“NSInvalidArgumentException”而终止应用程序,原因:“-[OS_dispatch_data 流:handleEvent:]:无法识别的选择器发送到实例 0x281be1b90”
线程 9 崩溃:0 libsystem_kernel.dylib 0x00000001bd5c7104 __pthread_kill + 8
1 libsystem_pthread.dylib 0x00000001bd643020 pthread_kill$VARIANT$mp + 376
2 libsystem_c.dylib 0x00000001bd51ed78 中止 + 136
3 大众-R-CLUB会员APP 0x00000001045603ac uncaught_exception_handler + 68
4 核心基础 0x00000001bda321e0 __handleUncaughtException + 688
5 libobjc.A.dylib 0x00000001bcc01e4c _objc_terminate() + 108
6 VW-R-CLUB会员APP 0x0000000104555c4c BITCrashUncaughtCXXerminateHandler() (BITCrashCXXExceptionHandler.mm:183)
7 libc++abi.dylib 0x00000001bcbf50fc std::__terminate(void (*)()) + 12
8 libc++abi.dylib 0x00000001bcbf5188 std::terminate() + 80
9 libdispatch.dylib 0x00000001bd46a498 _dispatch_client_callout + 32
10 libdispatch.dylib 0x00000001bd411bd0 _dispatch_lane_serial_drain$VARIANT$mp + 588
11 libdispatch.dylib 0x00000001bd41274c _dispatch_lane_invoke$VARIANT$mp + 480
12 libdispatch.dylib 0x00000001bd411a9c _dispatch_lane_serial_drain$VARIANT$mp + 280
13 libdispatch.dylib 0x00000001bd412718 _dispatch_lane_invoke$VARIANT$mp + 428
14 libdispatch.dylib 0x00000001bd41aeb8 _dispatch_workloop_worker_thread + 596
15 libsystem_pthread.dylib 0x00000001bd64d0dc _pthread_wqthread + 308
16 libsystem_pthread.dylib 0x00000001bd64fcec start_wqthread + 0
解决方案
首先,您显示的代码不是在 github 中找到的代码。您是同步 的所有用法_commandQueue
,还是仅同步这个?如果只有这一个,为什么其他的不同步?
然后,在 github 中,我发现了 的多种用法_commandQueue
,其中一些在名为async
... 的方法中,但也有一些不是async
,比如cancelPendingCommands
or responseCompleted
。您需要找出async
方法名称中的意图是什么,以及为什么方法 likecancelPendingCommands
不是不知何故async
。
更新
所以主要思想似乎是保护_commandQueue
串行内部的所有访问_dispatchQueue
。... 方法中已经是这种情况async
:它们是从该队列中调用的:
dispatch_async( _dispatchQueue, ^{
[self asyncEnqueueInternalCommand:internalCommand];
});
因此,您需要确保每次访问_commandQueue
都在此队列中排队,例如更改cancelPendingCommands
为类似
-(void)cancelPendingCommands
{
dispatch_async( _dispatchQueue, ^{
// This cancels all but the first command in order to prevent sending a new command while
// the response to an active command is still pending. OBD2 adapters usually can't cope with
// that and emit a 'STOPPED' response in that case.
if ( _hasPendingAnswer )
{
NSRange allButTheFirst = NSMakeRange( 1, _commandQueue.count - 1 );
[_commandQueue removeObjectsInRange:allButTheFirst];
}
else
{
[_commandQueue removeAllObjects];
}
});
}
(或创建一个专用asyncCancelPendingCommands
函数,该函数将从cancelPendingCommands
调度块内部调用。依此类推。
PS 如果你需要同步执行,你也可以使用dispatch_sync
而不是dispatch_async
,但是你必须确保你不会造成死锁。
推荐阅读
- javascript - 在“addEventListener”中调用时函数不起作用
- ios - 当我用逗号分隔电子邮件地址时如何添加文本气泡样式,如所附屏幕截图所示
- python - 如何获得 CatBoost 模型的系数?
- html - HTML/CSS 按钮有效,但除非刷新页面,否则不会显示任何效果
- html - 当我悬停一个弹性项目时如何实现这一点?
- typescript - 如何在 node_modules 中键入 JS 文件?
- iis - IIS 和证书,仅使用 netBOIS 名称保护本地访问的网站
- d3.js - 为什么 stack() 不在 d3.js 中创建访问器?
- android - 如何在 Kotlin 中合并流和通道?
- sed - 如何使用 sed 替换 config.yml 中以某种模式开头的特定值