Безопасность потока: NSOperationQueue + [массив addObject] - PullRequest
1 голос
/ 22 декабря 2011

Я не смог найти примеров того, как обращаться с той же (классовой) переменной, когда используется очередь операций.В C & Threads его о мьютексах.Итак, что происходит, когда NSOperationQueue запускает поток для операции и переменная класса изменяется?Это потокобезопасно?Спасибо.

@interface MyTest {
    NSMutableArray *_array;
}
@end

-(id)init
{
    ...
    _array = [NSMutableArray new]; // class variable

        // queue time consuming loading
    NSOperationQueue *queue = [NSOperationQueue new];
    NSInvocationOperation *operation =
        [NSInvocationOperation initWithTarget:self
                                     selector:@selector(populate)
                                       object:nil];
    [queue addOperation:operation];

        // start continuous processing
    [NSTimer scheduledTimerWithTimeInterval:0.1
                                     target:self
                                   selector:@selector(processing)
                                   userInfo:nil
                                    repeats:YES];
    ...
}

-(void)populate
{
    while (...)
    {
        id element = ...; // time consuming

            // modify class variable "_array" from operation's thread (?)
        [_array addObject:element];

            // Ok, I can do instead of addObject
            // performSelectorOnMainThread:withObject:waitUntilDone:
            // but is it the only way? Is it needed?
    }
}

    // access and/or modify class variable "_array"
-(void)processing
{
    NSLog(@"array.count = %d", array.count);
    for (id i in _array)
    {
        [_array addObject:[NSNumber numberWithInt:rand() % 100]];
            // etc...
    }
}

1 Ответ

1 голос
/ 22 декабря 2011

Нет, это не потокобезопасно, если вы запускаете поток, который выполняет некоторую работу с переменной класса, которая может быть изменена каким-либо другим потоком, то это не потокобезопасно, если обработка вызывается из какого-то потока, когда заполняется работаВ противном случае вы можете получить исключение, когда цикл foreach увидит, что массив был изменен, хотя вы все равно получите это исключение, когда будете изменять массив внутри цикла foreach в вашем примере (вы не должны этого делать, и программа сгенерируетисключение) ... Один из способов обойти это может быть с синхронизированным блоком в массиве, это гарантирует, что синхронизированные блоки не будут выполняться одновременно, поток блокируется до завершения одного синхронизированного блока, например

    -(void)populate
    {


        while (...)
        {
            id element = ...; // time consuming

                // modify class variable "_array" from operation's thread (?)
      @synchronized(_array)
        {
            [_array addObject:element];

        }          // Ok, I can do instead of addObject
                // performSelectorOnMainThread:withObject:waitUntilDone:
                // but is it the only way? Is it needed?
        }

    }

        // access and/or modify class variable "_array"
    -(void)processing
    {


          @synchronized(_array)
         {
            NSLog(@"array.count = %d", array.count);
            for (id i in _array)
            {
                //you shouldnt modify the _array here you will get an exception
                    // etc...
            }
        }
    }
...