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?
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];
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!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.
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];
}
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ą.
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
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.
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