2011-09-06 15 views
6

Ho un NSMutableArray che contiene molti oggetti.Cosa succede se NSMutableArray viene modificato da più thread contemporaneamente? (se gli oggetti che contiene sono conservati altrove)

Cosa succede se viene apportata una modifica all'array, mentre eseguo una copia dell'array utilizzando [NSMutableArray arrayWithArray: someArray];

Es .: se un oggetto viene rimosso dall'array mentre viene eseguita la copia?

Non so come testare questo scenario.

MODIFICA: gli oggetti non vengono rilasciati (poiché vengono mantenuti altrove). Ho appena usato questo array come tabella di ricerca.

+0

Ho avuto un problema simile due giorni fa, ma stavo rimuovendo gli elementi da una matrice ed enumerando in altro. Hai un'eccezione riguardo all'array che viene modificato. Se arrayWithArray: utilizza l'enumerazione rapida (non so), genererà un'eccezione. –

+0

Penso che tu capisca il mio problema! Sto cercando di determinare se verrà lanciata un'eccezione. Ma non riesco a creare un test per verificarlo poiché non riesco a coordinare un altro thread per modificare l'array mentre viene eseguita una copia. – xcoder

risposta

11

come sapete, il contenitore/raccolta non è garantito per essere sicuro. cosa può succedere se si modifica la matrice durante la copia o la lettura? molte cose. i casi ovvi sono che potrebbe essere riallocato al momento, potrebbe passare o restituire un riferimento non valido all'utente (ad esempio l'ultimo rimosso), oppure potrebbe accedere agli oggetti che sono stati rilasciati (da un altro thread). oltre a cose che potrebbero causare l'arresto anomalo dell'app o causare altri UB, potrebbe non restituire valori corretti o coerenti. è un'interpretazione errata dei dati. nessuno dei due è buono.

non si test lo scenario - problemi di threading sono difficili da riprodurre e davvero non si può mai coprire tutti i casi. poiché l'oggetto stesso non garantisce la sicurezza del thread - l'implementazione deve limitare accessi/mutazioni/interazioni a un thread alla volta. quando si ha a che fare con oggetti che sono usati in contesti multithread: ogni volta che accedete o richiedete informazioni dallo stato mutabile di un oggetto, dovreste proteggere l'oggetto (ad es. con un lucchetto). pertanto, è sufficiente bloccarlo mentre lo si utilizza. lock/copy/unlock/use copy è anche comune. per un NSMutableArray, gli esempi di stato mutabile sarebbero tutti i suoi oggetti e il suo conteggio. le sue operazioni e le sue mutazioni utilizzano anche lo stato mutabile dell'oggetto, quindi sono limitate.

se si utilizza questo oggetto solo da un thread, ovviamente non è necessario bloccarlo. questo è anche un motivo per cui passare per copia e tenere varianti immutabili sono entrambe buone idee nella maggior parte dei casi.non hai bisogno di un lucchetto per ogni oggetto, una protezione per l'oggetto che lo contiene è spesso un buon modo per progettare una classe per la sicurezza del filo.

Aggiornamento

... cosa succede? Ha la copia contiene tutti i 5 oggetti (dal momento che sono conservati altrove comunque? Fare contengono 4? (Anche contenente 4 è sufficiente per me) è un'eccezione gettata?

se non si è adeguatamente sorvegliato la raccolta, è . buono come comportamento non definito e si è fortunati se si blocca

è necessario prendere le opportune precauzioni per evitare un comportamento indefinito il programma sta funzionando in quel dominio quando non è adeguatamente sorvegliato

di elaborare..: mantenere gli oggetti esternamente riduce solo la probabilità di comportamento indefinito, ma certamente non lo elimina. Gli esempi di conseguenze includono eccezioni, segfaults, memoria di lettura o scrittura che viene utilizzata come un'altra allocazione attiva (che può apparire come problemi molto misteriosi che potrebbero anche essere virtualmente impossibili da riprodurre).

ti incoraggio a sorvegliare correttamente o ad adottare un altro approccio. UB è MALE :)

+0

Poiché gli oggetti non vengono rilasciati da alcun thread, sto cercando di capire cosa succede se un array viene modificato mentre [NSMutableArray arrayWithArray: (NSMutableArray *)] è in esecuzione. Ad esempio: 1. Se ho una matrice che ha 5 oggetti (mantenuta anche altrove). 2. Un altro thread tenta di creare una copia di questo array. 3. Un terzo thread modifica l'array originale (rimuove un oggetto). 4. Cosa succede? La copia contiene tutti e 5 gli oggetti (poiché sono conservati altrove in ogni caso? Contiene 4? (Anche contenendo 4 è sufficiente per me) Viene generata un'eccezione? – xcoder

+0

@xcoder aggiornato – justin

+1

Peccato che non riesca a tornare per il _undefined comportamento è male_aggiornamento –

5

Da Apple Docs:

oggetti mutabili sono generalmente non thread-safe. Per utilizzare gli oggetti mutabili in un'applicazione con il thread, l'applicazione deve sincronizzare l'accesso a questi utilizzando i blocchi. (Per ulteriori informazioni, consultare "Operazioni atomiche"). In generale, le classi di raccolta (ad esempio, NSMutableArray, NSMutableDictionary) non sono thread-safe quando si tratta di mutazioni. Cioè, se uno o più thread stanno cambiando lo stesso array, possono verificarsi problemi. È necessario bloccare i punti in cui si verificano letture e scritture per garantire la sicurezza del filo.

anche da Apple Docs:

Anche se “atomica” significa che l'accesso alla proprietà è thread-safe, semplicemente facendo tutte le proprietà della tua classe atomica non significa che la classe o più in generale il grafico dell'oggetto è "sicurezza thread-safe" non può essere espressa a livello di metodi di accesso individuali. Per ulteriori informazioni sul multithreading, vedere Guida alla programmazione del threading.

+0

Ho letto i documenti Apple, ma non è chiaro per me cosa succede realmente in questo scenario. Poiché è difficile ottenere i due thread per eseguire le operazioni in sincrono, non riesco a vedere quale problema si verificherà. – xcoder

+0

Consultare la sezione: "Uso della direttiva @ sincronizzata" nella guida alla programmazione del threading. Vedi anche questa risposta: http://stackoverflow.com/questions/3521190/synchronizing-nsmutablearray-for-thread-security – sosborn

+0

So a cosa serve @synchronized. La guida parla di cose brutte che possono accadere quando un oggetto a cui si accede da un thread, viene rilasciato da un altro thread. Poiché i miei oggetti non vengono rilasciati da nessuno dei thread, cosa accade se un array contenente riferimenti a un oggetto viene modificato mentre viene eseguita una copia? Non penso che ci possa essere uno scenario di "puntatori penzolanti", perché gli oggetti stessi vengono mantenuti altrove, quindi qualsiasi puntatore che punta all'oggetto dovrebbe essere valido. cosa succede a questo array, se viene modificato quando viene eseguita una copia? – xcoder

0

Se removeObject viene chiamato contemporaneamente a arrayWithArray, il programma si bloccherà. Se si utilizza la sincronizzazione, forzando removeObject a essere eseguito appena prima o subito dopo arrayWithArray, non è possibile sapere quanti oggetti avrà il nuovo array. Questo non si bloccherà immediatamente, ma cosa farà il tuo codice? Devi essere molto chiaro nella tua mente che il risultato di [NSArray arrayWithArray: someArray] è un array che non contiene il contenuto di someArray in questo momento, ma il contenuto di someArray ad un certo punto nel passato.

Problemi correlati