Как исправить это состояние гонки в Objective C / асинхронной проблеме?'индекс 1 за пределами для пустого массива' - PullRequest
0 голосов
/ 11 февраля 2019

Привет, у меня есть проблема с этой библиотекой: LTSupportAutomotive

Я быстрый программист, поэтому не очень хорош в цели c.

как исправить это состояние гонки?

Я надеюсь, что кто-то может мне помочь.

'*** - [__ NSArrayM insertObject: atIndex:]: индекс 1 вне границ для пустого массива'

-(void)asyncEnqueueInternalCommand:(LTOBD2AdapterInternalCommand*)internalCommand
{
    @synchronized(self) {
        [_commandQueue addObject:internalCommand];
    }
}

Источниккод:

https://github.com/mickeyl/LTSupportAutomotive/blob/f51b962421f211ee6af5c733f79190117d7cac5e/LTSupportAutomotive/LTOBD2Adapter.m

ОБНОВЛЕНИЕ 1:

Создана ветка с первыми исправлениями: https://github.com/Skyb0rg/LTSupportAutomotive/tree/BugfixMemoryManagement

Последобавив дополнительную командуQueue я получил новые ошибки:

в LTBTLEWriteCharacteristicStream.m

-(void)characteristicDidWriteValue
{
    [self.delegate stream:self handleEvent:NSStreamEventHasSpaceAvailable];
}

эта функция падает с: Имя селектора, найденное в текущих регистрах аргументов: делегат

Поток 6Разбился: 0 libobjc.A.dylib 0x00000001bcc19430 objc_retain + 16 * +1031 *

1 LTSupportAutomotive 0x00000001093c2a34 - [LTBTLEWriteCharacteristicStream characteristicDidWriteValue] (LTBTLEWriteCharacteristicStream.m: 39)

2 LTSupportAutomotive 0x00000001093c2714 - [LTBTLESerialTransporter периферическое: didWriteValueForCharacteristic: ошибка:] (LTBTLESerialTransporter.m: 311)

3 CoreBluetooth 0x00000001c35e6ce0 - [CBPeripheral handleAttributeEvent: args: attributeSelector: DelegateSelector: DelegateFlag:] + 236

4 CoreBluetooth 0x00000001c35e6e40 - [CBPeripheral handleCharacteristicEvent: характеристика: Выбор: делегатSelector: DelegateFlag:] + 128

5 дескриптор CB0B0: 0352

6 CoreBluetooth 0x00000001c35dcbfc - [CBCentralManager handleMsg: args:] + 200

7 CoreBluetooth 0x00000001c35eb770 __30- [CBXpcConnection _handleMsg:] 566 * 0 * * 0 * 0 0 0 8 0 0 0 0 0 0 0 0 0 0 8 0 0 0 6 6 6 6 6 0 0 0 6 6 6 6 6 6 6 6 0 0 0 6 6 6 6 6 6 0 0 5 6 5 0 0 0 0 0 6 0 0 0 6 6 6 6 6 6 6 6 6 0_dispatch_call_block_and_release + 20

* * 9 тысяча сорок-восемь libdispatch.dylib 0x00000001bd46a484 _dispatch_client_callout + 12

10 libdispatch.dylib 0x00000001bd411bd0 _dispatch_lane_serial_drain $ ВАРИАНТ $ т.пл + 588

* * +1052 11 libdispatch.dylib 0x00000001bd41274c _dispatch_lane_invoke $ ВАРИАНТ $mp + 480

12 libdispatch.dylib 0x00000001bd411a9c _dispatch_lane_serial_drain $ VARIANT $ mp + 280

13 libdispatch.dylib 0x00000001bd412718 _dispatch_lane_inВАРИАНТ $ т.пл + 428 * * * тысяча пятьдесят-семите 1058 * 14 libdispatch.dylib 0x00000001bd41aeb8 _dispatch_workloop_worker_thread + 596 * * * тысяча пятьдесят-девять 1060 * 15 libsystem_pthread.dylib 0x00000001bd64d0dc _pthread_wqthread + 308 * 1 061 * * * +1062 16 libsystem_pthread.dylib 0x00000001bd64fcec start_wqthread + 0 * 1 063 *

и еще один сбой в : LTBTLEReadCharacteristicStream.m

-(void)characteristicDidUpdateValue
{
        NSData* value = _characteristic.value;
        [_buffer appendData:value];
        [self.delegate stream:self handleEvent:NSStreamEventHasBytesAvailable];
}

*** Завершение работы приложения из-за необработанного исключения «NSInvalidArgumentException», причина: '- [поток OS_dispatch_data: handleEvent:]: непризнанные селектор направил к экземпляру 0x281be1b90'

1071 * тема 9 Разбился: 0 libsystem_kernel.dylib 0x00000001bd5c7104 __pthread_kill + 8

1 libsystem_pthread.dylib 0x00000001bd643020 pthread_kill $ ВАРИАНТ $ тр + 376

1075 *2 libsystem_c.dylib 0x00000001bd51ed78 abort + 136

3 APP члена VW-R-CLUB 0x00000001045603ac uncaught_exception_handler + 68

4 CoreFoundation 0x00000001bda321e0 68b * * *0x00000001bcc01e4c_objc_terminate () + 108

6 Приложение-член VW-R-CLUB 0x0000000104555c4c BITCrashUncaughtCXXTerminateHandler () (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 $ ВАРИАНТ $ т.пл + 588

11 libdispatch.dylib 0x00000001bd41274c _dispatch_lane_invoke $ VARIANT $ т.пл. + 480

12 libdispatch.dylib 0x00000001bd411a9c _dispatch_lane_serial_drain $ ВАРИАНТ $ т.пл + 280

13 libdispatch.dylib 0x00000001bd412718 _dispatch_lane_invoke $ ВАРИАНТ $ т.пл + 428 * * * одна тысяча девяносто восемь 1099 * 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

1 Ответ

0 голосов
/ 11 февраля 2019

Во-первых, код, который вы показываете, не тот, который можно найти в github.Вы синхронизируете все случаи использования _commandQueue или только этот?Если только этот, почему другие не синхронизируются?

Затем, в github я нахожу многократные использования _commandQueue, некоторые из них в методах с именем async ..., но также некоторыене async, как cancelPendingCommands или responseCompleted.Вам необходимо выяснить, что означает async в имени метода, и почему такие методы, как cancelPendingCommands, не так или иначе 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, но тогда вам нужно убедиться, что вы не создаете взаимоблокировки.

...