Czy wątek Nsmutablearray Objective-C jest bezpieczny?

Próbuję naprawić ten wypadek od prawie tygodnia. Aplikacja ulega awarii bez wyjątku lub śledzenia stosu. Aplikacja nie zawiesza się w żaden sposób podczas pracy przez instrumenty w trybie zombie.

Mam metodę, która jest wywoływana w innym wątku. Rozwiązanie, które naprawiło awarię, zastępowało
[self.mutableArray removeAllObjects];

Z

dispatch_async(dispatch_get_main_queue(), ^{
    [self.searchResult removeAllObjects];
});

Myślałem, że to może być problem z czasem, więc próbowałem go zsynchronizować, ale nadal rozbity:

@synchronized(self)
{
    [self.searchResult removeAllObjects];
}

Oto kod

- (void)populateItems
{
   // Cancel if already exists  
   [self.searchThread cancel];

   self.searchThread = [[NSThread alloc] initWithTarget:self
                                               selector:@selector(populateItemsinBackground)
                                                 object:nil];

    [self.searchThread start];
}


- (void)populateItemsinBackground
{
    @autoreleasepool
    {
        if ([[NSThread currentThread] isCancelled])
            [NSThread exit];

        [self.mutableArray removeAllObjects];

        // Populate data here into mutable array

        for (loop here)
        {
            if ([[NSThread currentThread] isCancelled])
                [NSThread exit];

            // Add items to mutableArray
        }
    }
}

Czy ten problem z NSMutableArray nie jest bezpieczny dla wątków?

Author: Peter Mortensen, 2012-08-23

7 answers

Nie.

Nie jest bezpieczny dla wątku i jeśli chcesz zmodyfikować zmienną tablicę z innego wątku, powinieneś użyć NSLock, aby upewnić się, że wszystko idzie zgodnie z planem:

NSLock *arrayLock = [[NSLock alloc] init];

[...] 

[arrayLock lock]; // NSMutableArray isn't thread-safe
[myMutableArray addObject:@"something"];
[myMutableArray removeObjectAtIndex:5];
[arrayLock unlock];
 89
Author: Daniel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-23 18:57:10

Jak już powiedzieli inni, NSMutableArray nie jest bezpieczny dla wątków. Jeśli ktoś chce osiągnąć więcej niż removeAllObject w środowisku bezpiecznym dla wątku, podam inne rozwiązanie przy użyciu GCD oprócz tego przy użyciu Locka. To, co musisz zrobić, to zsynchronizować operacje odczytu/aktualizacji(zastąp / Usuń).

Najpierw get the global concurrent queue:

dispatch_queue_t concurrent_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

Do czytania:

- (id)objectAtIndex:(NSUInteger)index {
    __block id obj;
    dispatch_sync(self.concurrent_queue, ^{
        obj = [self.searchResult objectAtIndex:index];
    });
    return obj;
}

Dla insert:

- (void)insertObject:(id)obj atIndex:(NSUInteger)index {
    dispatch_barrier_async(self.concurrent_queue, ^{
        [self.searchResult insertObject:obj atIndex:index];
    });
}

From Apple Doc about dispatch_barrier_async:

Gdy blok barierowy dociera do przodu prywatnej kolejki współbieżnej, nie jest wykonywany od razu. Zamiast tego Kolejka czeka aż aktualnie wykonywane bloki zakończą wykonywanie. W tym momencie blok barierowy wykonuje się sam. Wszelkie bloki przesłane po bloku barierowym nie są wykonywane, dopóki blok barierowy się nie zakończy.

Podobne do Usuń:

- (void)removeObjectAtIndex:(NSUInteger)index {
    dispatch_barrier_async(self.concurrent_queue, ^{
        [self.searchResult removeObjectAtIndex:index];
    });
}

EDIT: właściwie znalazłem dziś inny prostszy sposób synchronizacji dostępu do zasobu za pomocą szeregowego Kolejka dostarczona przez GCD.

From Apple Doc Concurrency Programming Guide > Dispatch Queues :

Kolejki seryjne są przydatne, gdy chcesz, aby Twoje zadania wykonywały się w określonej kolejności. Kolejka szeregowa wykonuje tylko jedno zadanie na raz i zawsze ściąga zadania z początku kolejki. Możesz użyć kolejki szeregowej zamiast blokady, aby chronić współdzielony Zasób lub zmienną strukturę danych. W przeciwieństwie do blokady, Kolejka szeregowa zapewnia, że zadania są wykonywane w przewidywalnym spokój. I tak długo, jak przesyłasz swoje zadania do kolejki szeregowej asynchronicznie, kolejka nie może się zablokować.

Tworzenie kolejki szeregowej:

dispatch_queue_t myQueue = dispatch_queue_create("com.example.MyQueue", NULL);

Wysyłanie zadań asynchronicznych do kolejki szeregowej:

dispatch_async(myQueue, ^{
    obj = [self.searchResult objectAtIndex:index];
});

dispatch_async(myQueue, ^{
    [self.searchResult removeObjectAtIndex:index];
});
Mam nadzieję, że to pomoże!
 38
Author: Jingjie Zhan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-31 23:53:43

Jak również {[0] } można również użyć @synchronized(condition-object ) musisz tylko upewnić się, że każdy dostęp do tablicy jest zawinięty w {[1] } z tym samym obiektem działającym jako condition-object , jeśli chcesz tylko zmodyfikować zawartość tej samej instancji tablicy, możesz użyć samej tablicy jako condition-object, innym sposobem będziesz musiał użyć czegoś innego, o czym wiesz, że nie odejdzie, obiekt nadrzędny, czyli self, jest dobrym wyborem, ponieważ zawsze będzie to obiekt nadrzędny. ten sam dla tej samej tablicy.

Atrybuty atrybutu Atomic in @property sprawią, że ustawienie wątku tablicy będzie bezpieczne, nie zmieniając zawartości, tzn. self.mutableArray=... czy wątek jest bezpieczny, ale [self.mutableArray removeObject:] nie jest.

 20
Author: Nathan Day,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-29 19:26:14
__weak typeof(self)weakSelf = self;

 @synchronized (weakSelf.mutableArray) {
     [weakSelf.mutableArray removeAllObjects];
 }
 13
Author: sash,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-06-03 10:52:03

Skoro wspomniano o kolejkach szeregowych: z zmienną tablicą, samo pytanie "czy wątek jest bezpieczny" nie wystarczy. Na przykład upewnienie się, że removeAllObjects nie ulegnie awarii jest dobre i dobre, ale jeśli inny wątek spróbuje przetworzyć tablicę w tym samym czasie, przetworzy tablicę Przed lub po wszystkie elementy zostaną usunięte i naprawdę musisz pomyśleć, jakie powinno być zachowanie.

Tworzenie jednej klasy + obiektu, który jest odpowiedzialny za tę tablicę, tworzenie kolejki szeregowej dla niej i wykonywanie wszystkich operacji za pośrednictwem klasy w tej kolejce szeregowej jest najprostszym sposobem, aby wszystko było dobrze bez powodowania bólu mózgu przez problemy z synchronizacją.

 5
Author: gnasher729,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-18 23:54:21

Wszystkie klasy NSMutablexxx nie są bezpieczne dla wątków. Operacje takie jak get,insert,remove,add I replace powinny być używane z NSLock.To jest lista klas thread-safe I thread-unsafe podanych przez apple: thread Safety Summary

 1
Author: holybiner,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-17 15:23:45

Prawie nsmutable classes object nie jest bezpieczny dla wątku.

 0
Author: Hardeep Singh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-23 18:44:26