¿Cuál es la diferencia entre los atributos atómicos y no atómicos?

Respuestas:

1761

Los dos últimos son idénticos; "atómico" es el comportamiento predeterminado ( tenga en cuenta que en realidad no es una palabra clave; se especifica solo por la ausencia denonatomic -atomic se agregó como palabra clave en versiones recientes de llvm / clang).

Suponiendo que está sintetizando las implementaciones del método, atómico vs. no atómico cambia el código generado. Si está escribiendo su propio setter / getters, atómico / no atómico / retener / asignar / copiar son meramente informativos. (Nota: @synthesize es ahora el comportamiento predeterminado en las versiones recientes de LLVM. Tampoco es necesario declarar las variables de instancia; también se sintetizarán automáticamente y se agregarán _previamente a su nombre para evitar el acceso directo accidental).

Con "atómico", el setter / getter sintetizado asegurará que todo el setter siempre devuelva valor o que el setter lo devuelva, independientemente de la actividad del setter en cualquier otro hilo. Es decir, si el subproceso A está en el medio del captador mientras el subproceso B llama al establecedor, un valor viable real, un objeto lanzado automáticamente, muy probablemente, se devolverá al llamante en A.

En nonatomic, no se hacen tales garantías. Por lo tanto, nonatomices considerablemente más rápido que "atómico".

Lo que "atomic" no hace es garantizar la seguridad de los hilos. Si el subproceso A está llamando al captador simultáneamente con el subproceso B y C llamando al establecedor con valores diferentes, el subproceso A puede obtener cualquiera de los tres valores devueltos, el anterior a cualquier llamada de los establecedores o cualquiera de los valores pasados ​​a los establecedores en B y C. Del mismo modo, el objeto puede terminar con el valor de B o C, no hay forma de saberlo.

Garantizar la integridad de los datos, uno de los principales desafíos de la programación multiproceso, se logra por otros medios.

Agregando a esto:

atomicity de una sola propiedad tampoco puede garantizar la seguridad del subproceso cuando varias propiedades dependientes están en juego.

Considerar:

 @property(atomic, copy) NSString *firstName;
 @property(atomic, copy) NSString *lastName;
 @property(readonly, atomic, copy) NSString *fullName;

En este caso, el hilo A podría renombrar el objeto llamando setFirstName:y luego llamando setLastName:. Mientras tanto, el hilo B puede llamar fullNameentre las dos llamadas del hilo A y recibirá el nuevo nombre junto con el apellido anterior.

Para abordar esto, necesita un modelo transaccional . Es decir, algún otro tipo de sincronización y / o exclusión que le permita a uno excluir el acceso fullNamemientras se actualizan las propiedades dependientes.

bbum
fuente
21
Dado que cualquier código seguro para subprocesos hará su propio bloqueo, etc., ¿cuándo desea utilizar los accesores de propiedades atómicas? Tengo problemas para pensar en un buen ejemplo.
Daniel Dickison
8
@bbum tiene sentido. Me gusta su comentario a otra respuesta de que la seguridad del hilo es más una preocupación a nivel de modelo. De una definición de seguridad de subprocesos de IBM: ibm.co/yTEbjY "Si una clase se implementa correctamente, que es otra forma de decir que se ajusta a su especificación, no hay secuencia de operaciones (lecturas o escrituras de campos públicos y llamadas a métodos públicos) en objetos de esa clase debería poder poner el objeto en un estado inválido, observar que el objeto está en un estado inválido o violar cualquiera de los invariantes, precondiciones o postcondiciones de la clase ".
Ben Flynn
66
Aquí hay un ejemplo similar al de @StevenKramer: Tengo una @property NSArray* astronomicalEvents;lista de datos que quiero mostrar en la interfaz de usuario. Cuando la aplicación inicia el puntero apunta a una matriz vacía, la aplicación extrae datos de la web. Cuando se completa la solicitud web (en un hilo diferente), la aplicación crea una nueva matriz y luego establece atómicamente la propiedad en un nuevo valor de puntero. Es seguro para subprocesos y no tuve que escribir ningún código de bloqueo, a menos que me falte algo. Me parece bastante útil.
bugloaf
10
@HotLicks Otra divertida; En ciertas arquitecturas (no recuerdo cuál), los valores de 64 bits pasados ​​como argumento podrían pasar la mitad en un registro y la mitad en la pila. atomicevita lecturas de valor medio entre hilos. (Ese fue un error divertido de rastrear.)
bbum
8
@congliu El hilo A devuelve un objeto sin retain/autoreleasebailar. El hilo B libera el objeto. Hilo A va boom . atomicasegura que el hilo A tenga una referencia fuerte (un recuento de retención +1) para el valor de retorno.
bbum
360

Esto se explica en la documentación de Apple , pero a continuación hay algunos ejemplos de lo que realmente está sucediendo.

Tenga en cuenta que no hay una palabra clave "atómica", si no especifica "no atómica", entonces la propiedad es atómica, pero si especifica "atómica" explícitamente se producirá un error.

Si no especifica "no atómico", la propiedad es atómica, pero aún puede especificar "atómico" explícitamente en las versiones recientes si lo desea.

//@property(nonatomic, retain) UITextField *userName;
//Generates roughly

- (UITextField *) userName {
    return userName;
}

- (void) setUserName:(UITextField *)userName_ {
    [userName_ retain];
    [userName release];
    userName = userName_;
}

Ahora, la variante atómica es un poco más complicada:

//@property(retain) UITextField *userName;
//Generates roughly

- (UITextField *) userName {
    UITextField *retval = nil;
    @synchronized(self) {
        retval = [[userName retain] autorelease];
    }
    return retval;
}

- (void) setUserName:(UITextField *)userName_ {
    @synchronized(self) {
      [userName_ retain];
      [userName release];
      userName = userName_;
    }
}

Básicamente, la versión atómica tiene que tomar un candado para garantizar la seguridad del hilo, y también está aumentando el recuento de referencia en el objeto (y el recuento de liberación automática para equilibrarlo) de modo que se garantice que el objeto exista para la persona que llama, de lo contrario es una posible condición de carrera si otro subproceso está configurando el valor, lo que hace que el recuento de referencias caiga a 0.

En realidad, hay una gran cantidad de variantes diferentes de cómo funcionan estas cosas dependiendo de si las propiedades son valores u objetos escalares, y cómo interactúan los elementos de retención, copia, solo lectura, no atómico, etc. En general, los sintetizadores de propiedades simplemente saben cómo hacer "lo correcto" para todas las combinaciones.

Louis Gerbarg
fuente
8
@ Louis Gerbarg: Creo que su versión del configurador (no atómico, retener) no funcionará correctamente si intenta asignar el mismo objeto (es decir: userName == userName_)
Florin
55
Su código es un poco engañoso; no hay garantía sobre qué getters / setters atómicos están sincronizados. Críticamente, @property (assign) id delegate;no está sincronizado en nada (iOS SDK GCC 4.2 ARM -Os), lo que significa que hay una carrera entre [self.delegate delegateMethod:self];y foo.delegate = nil; self.foo = nil; [super dealloc];. Ver stackoverflow.com/questions/917884/…
tc.
@fyolnish No estoy seguro de qué _val/ valson, pero no, en realidad no. El captador para un atómica copy/ retainpropiedad necesita para asegurarse de que no devuelve un objeto cuya refcount se convierte en cero debido al colocador de ser llamado en otro hilo, que esencialmente significa que necesita para leer el Ivar, consérvelo garantizando al mismo tiempo que el colocador no tiene sobrescrito y liberado, y luego liberarlo automáticamente para equilibrar la retención. Eso significa esencialmente que tanto el getter como el setter tienen que usar un bloqueo (si se reparó el diseño de la memoria, debería ser posible con las instrucciones CAS2; por desgracia, -retaines una llamada al método).
tc.
@tc Ha pasado bastante tiempo, pero lo que quise escribir fue probablemente esto: gist.github.com/fjolnir/5d96b3272c6255f6baae Pero sí, es posible que un lector lea el valor anterior antes de setFoo: devuelve y se libera antes del El lector lo devuelve. Pero tal vez si el setter usa -autorelease en lugar de -release, eso solucionaría eso.
Fjölnir
@fyolnish Desafortunadamente, no: eso se libera automáticamente en el subproceso del configurador, mientras que debe relanzarse automáticamente en el subproceso del captador. También parece que hay una posibilidad (escasa) de quedarse sin pila porque estás usando la recursividad.
tc.
170

Atómico

  • es el comportamiento predeterminado
  • asegurará que la CPU complete el proceso actual, antes de que otro proceso acceda a la variable
  • no es rápido, ya que garantiza que el proceso se complete por completo

No atómico

  • NO es el comportamiento predeterminado
  • más rápido (para código sintetizado, es decir, para variables creadas usando @property y @synthesize)
  • no es seguro para subprocesos
  • puede provocar un comportamiento inesperado, cuando dos procesos diferentes acceden a la misma variable al mismo tiempo
raw3d
fuente
137

La mejor manera de entender la diferencia es usar el siguiente ejemplo.

Supongamos que hay una propiedad de cadena atómica llamada "nombre", y si llama [self setName:@"A"]desde el hilo A, llama [self setName:@"B"]desde el hilo B y llama [self name]desde el hilo C, entonces todas las operaciones en diferentes hilos se realizarán en serie, lo que significa que si un hilo está ejecutando un setter o getter, entonces otros hilos esperarán.

Esto hace que la propiedad "nombre" de lectura / escritura sea segura, pero si otro subproceso, D, llama [name release]simultáneamente, entonces esta operación puede producir un bloqueo porque no hay una llamada de setter / getter involucrada aquí. Lo que significa que un objeto es seguro para lectura / escritura (ATOMIC), pero no para subprocesos, ya que otros subprocesos pueden enviar simultáneamente cualquier tipo de mensajes al objeto. El desarrollador debe garantizar la seguridad del hilo para tales objetos.

Si la propiedad "nombre" no era atómica, entonces todos los hilos en el ejemplo anterior - A, B, C y D se ejecutarán simultáneamente produciendo cualquier resultado impredecible. En caso de atómica, cualquiera de A, B o C se ejecutará primero, pero D aún puede ejecutarse en paralelo.

Vijayendra
fuente
116

La sintaxis y la semántica ya están bien definidas por otras excelentes respuestas a esta pregunta. Como la ejecución y el rendimiento no están bien detallados, agregaré mi respuesta.

¿Cuál es la diferencia funcional entre estos 3?

Siempre había considerado atómico como un defecto bastante curioso. En el nivel de abstracción en el que trabajamos, el uso de propiedades atómicas para una clase como vehículo para lograr un 100% de seguridad de roscas es un caso de esquina. Para programas multiproceso verdaderamente correctos, la intervención del programador es casi un requisito. Mientras tanto, las características de rendimiento y ejecución aún no se han detallado en profundidad. Habiendo escrito algunos programas muy multiproceso a lo largo de los años, había estado declarando mis propiedades nonatomictodo el tiempo porque atomic no era sensato para ningún propósito. Durante la discusión de los detalles de las propiedades atómicas y no atómicas de esta pregunta , hice algunos perfiles y encontré algunos resultados curiosos.

Ejecución

Okay. Lo primero que me gustaría aclarar es que la implementación de bloqueo está definida y resumida en la implementación. Louis usa @synchronized(self)en su ejemplo: he visto esto como una fuente común de confusión. La implementación en realidad no usa @synchronized(self); utiliza bloqueos de giro a nivel de objeto . La ilustración de Louis es buena para una ilustración de alto nivel que utiliza construcciones con las que todos estamos familiarizados, pero es importante saber que no se usa @synchronized(self).

Otra diferencia es que las propiedades atómicas retendrán / liberarán el ciclo de sus objetos dentro del captador.

Actuación

Aquí está la parte interesante: el rendimiento mediante el acceso a propiedades atómicas en casos no disputados (por ejemplo, de un solo subproceso) puede ser realmente muy rápido en algunos casos. En casos menos que ideales, el uso de accesos atómicos puede costar más de 20 veces la sobrecarga de nonatomic. Mientras que el caso impugnado con 7 subprocesos fue 44 veces más lento para la estructura de tres bytes ( Core i7 Quad Core de 2.2 GHz , x86_64). La estructura de tres bytes es un ejemplo de una propiedad muy lenta.

Nota al margen interesante: los accesores definidos por el usuario de la estructura de tres bytes fueron 52 veces más rápidos que los accesos atómicos sintetizados; o 84% de la velocidad de los accesos no atómicos sintetizados.

Los objetos en casos disputados también pueden exceder 50 veces.

Debido a la cantidad de optimizaciones y variaciones en las implementaciones, es bastante difícil medir los impactos del mundo real en estos contextos. A menudo puede escuchar algo como "Confía en él, a menos que hagas un perfil y descubras que es un problema". Debido al nivel de abstracción, en realidad es bastante difícil medir el impacto real. Obtener los costos reales de los perfiles puede llevar mucho tiempo y, debido a las abstracciones, ser bastante inexactos. Además, ARC vs MRC puede hacer una gran diferencia.

Entonces, retrocedamos, sin centrarnos en la implementación de accesos a la propiedad, incluiremos los sospechosos habituales objc_msgSend, y examinaremos algunos resultados de alto nivel del mundo real para muchas llamadas a un NSStringcaptador en casos no controvertidos (valores en segundos):

  • MRC | no atómico | getters implementados manualmente: 2
  • MRC | no atómico | getter sintetizado: 7
  • MRC | atómico | getter sintetizado: 47
  • ARC | no atómico | getter sintetizado: 38 (nota: ARC agrega ciclismo de recuento de referencia aquí)
  • ARC | atómico | getter sintetizado: 47

Como probablemente haya adivinado, la actividad de conteo de referencia / ciclismo es un contribuyente significativo con los atómicos y bajo ARC. También vería mayores diferencias en los casos disputados.

Aunque presto mucha atención al rendimiento, sigo diciendo ¡ Semántica primero! . Mientras tanto, el rendimiento es de baja prioridad para muchos proyectos. Sin embargo, conocer los detalles de ejecución y los costos de las tecnologías que usa ciertamente no hace daño. Debe usar la tecnología adecuada para sus necesidades, propósitos y habilidades. Esperemos que esto le ahorre algunas horas de comparación y lo ayude a tomar una decisión mejor informada al diseñar sus programas.

justin
fuente
MRC | atómico | getter sintetizado: 47 ARC | atómico | getter sintetizado: 47 ¿Qué los hace iguales? ¿No debería ARC tener más gastos generales?
SDEZero
2
Entonces, si las propiedades atómicas son malas y son predeterminadas. Para aumentar el código repetitivo?
Kunal Balani
@ LearnCocos2D que acabo de probar en 10.8.5 en la misma máquina, apuntando a 10.8, para el caso único no disputado con un NSStringque no es inmortal: -ARC atomic (BASELINE): 100% -ARC nonatomic, synthesised: 94% -ARC nonatomic, user defined: 86% -MRC nonatomic, user defined: 5% -MRC nonatomic, synthesised: 19% -MRC atomic: 102%los resultados son un poco diferentes hoy en día. No estaba haciendo ninguna @synchronizedcomparación. @synchronizedes semánticamente diferente, y no lo considero una buena herramienta si tiene programas concurrentes no triviales. si necesitas velocidad, evita @synchronized.
Justin
¿Tienes esta prueba en línea en alguna parte? Sigo agregando el mío aquí: github.com/LearnCocos2D/LearnCocos2D/tree/master/…
LearnCocos2D
@ LearnCocos2D no los he preparado para el consumo humano, lo siento.
justin
95

Atómico = seguridad del hilo

No atómico = Sin seguridad de hilo

Hilo de seguridad:

Las variables de instancia son seguras para subprocesos si se comportan correctamente cuando se accede desde múltiples subprocesos, independientemente de la programación o intercalación de la ejecución de esos subprocesos por el entorno de tiempo de ejecución, y sin sincronización adicional u otra coordinación por parte del código de llamada.

En nuestro contexto:

Si un hilo cambia el valor de la instancia, el valor cambiado está disponible para todos los hilos, y solo un hilo puede cambiar el valor a la vez.

Donde utilizar atomic:

si se va a acceder a la variable de instancia en un entorno multiproceso.

Implicación de atomic:

No tan rápido como nonatomicporque nonatomicno requiere ningún trabajo de vigilancia en el tiempo de ejecución.

Donde utilizar nonatomic:

Si la variable de instancia no va a ser cambiada por múltiples hilos, puede usarla. Mejora el rendimiento.

Durai Amuthan.H
fuente
3
Todo lo que dices aquí es correcto, pero la última oración es esencialmente "incorrecta", Dura, para la programación de hoy. Es realmente inconcebible que te molestes en tratar de "mejorar el rendimiento" de esta manera. (Quiero decir, antes de llegar a años luz de eso, estarías "sin usar ARC", "¡sin usar NSString porque es lento!", Etc.) Para hacer un ejemplo extremo, sería como decir "equipo, no ponga ningún comentario en el código, ya que nos ralentiza ". No hay una tubería de desarrollo realista en la que desee las ganancias de rendimiento teórico (inexistentes) en aras de la falta de confiabilidad.
Fattie
3
@JoeBlow es un hecho, puede verificarlo aquí developer.apple.com/library/mac/documentation/Cocoa/Conceptual/…
Durai Amuthan.H
1
Durai, FWIW, ese enlace contradice directamente su tesis de "Atómica = seguridad de hilo". En el documento, Apple dice explícitamente: "La atomicidad de la propiedad no es sinónimo de la seguridad del hilo de un objeto". En la práctica, atomic rara vez es suficiente para lograr la seguridad del hilo.
Rob
69

Encontré una explicación bastante bien puesta de las propiedades atómicas y no atómicas aquí . Aquí hay un texto relevante del mismo:

'atómico' significa que no se puede descomponer. En términos de SO / programación, una llamada de función atómica es aquella que no se puede interrumpir: toda la función debe ejecutarse y no cambiarse de la CPU por el cambio de contexto habitual del SO hasta que se complete. En caso de que no lo supiera: dado que la CPU solo puede hacer una cosa a la vez, el sistema operativo gira el acceso a la CPU a todos los procesos en ejecución en pequeños intervalos de tiempo, para dar la ilusiónmultitarea. El programador de la CPU puede (y lo hace) interrumpir un proceso en cualquier punto de su ejecución, incluso en una llamada de función media. Entonces, para acciones como actualizar variables de contador compartidas donde dos procesos podrían intentar actualizar la variable al mismo tiempo, deben ejecutarse 'atómicamente', es decir,

Entonces, supongo que atómico en este caso significa que los métodos del lector de atributos no se pueden interrumpir, lo que significa que las variables que se leen por el método no pueden cambiar su valor a la mitad porque algún otro subproceso / llamada / función obtiene intercambiado en la CPU.

Debido a que las atomicvariables no pueden ser interrumpidas, se garantiza que el valor contenido en ellas en cualquier punto (bloqueo de hilo) no se corrompe , aunque garantizar que este bloqueo de hilo haga que el acceso a ellas sea más lento. non-atomicLas variables, por otro lado, no ofrecen tal garantía, pero ofrecen el lujo de un acceso más rápido. Para resumir, vaya non-atomiccuando sepa que sus variables no serán accedidas por múltiples hilos simultáneamente y acelerará las cosas.

tipycalFlow
fuente
1
El enlace está roto. ; (
Rob
Ese es el problema con los enlaces :( por suerte, he citado el texto relevante en mi respuesta
tipycalFlow
67

Después de leer tantos artículos, publicaciones de Stack Overflow y hacer aplicaciones de demostración para verificar los atributos de las propiedades variables, decidí juntar toda la información de los atributos:

  1. atomic // Defecto
  2. nonatomic
  3. strong = retain // Defecto
  4. weak = unsafe_unretained
  5. retain
  6. assign // Defecto
  7. unsafe_unretained
  8. copy
  9. readonly
  10. readwrite // Defecto

En el artículo Atributos o modificadores de propiedades variables en iOS , puede encontrar todos los atributos mencionados anteriormente, y eso definitivamente lo ayudará.

  1. atomic

    • atomic significa que solo un hilo accede a la variable (tipo estático).
    • atomic es seguro para hilos.
    • Pero es lento en rendimiento
    • atomic es el comportamiento predeterminado
    • Los accesores atómicos en un entorno sin recolección de basura (es decir, cuando se usa retención / liberación / liberación automática) usarán un bloqueo para garantizar que otro hilo no interfiera con la configuración / obtención correcta del valor.
    • En realidad no es una palabra clave.

    Ejemplo:

        @property (retain) NSString *name;
    
        @synthesize name;
  2. nonatomic

    • nonatomic significa acceso múltiple a la variable (tipo dinámico).
    • nonatomic no es seguro para subprocesos
    • Pero es rápido en rendimiento
    • nonatomicNO es un comportamiento predeterminado. Necesitamos agregar la nonatomicpalabra clave en el atributo de propiedad.
    • Puede dar lugar a un comportamiento inesperado, cuando dos procesos diferentes (subprocesos) acceden a la misma variable al mismo tiempo.

    Ejemplo:

        @property (nonatomic, retain) NSString *name;
    
        @synthesize name;
swiftBoy
fuente
¿Cómo pueden asignarse y fuertes / retener ambos por defecto?
BangOperator
fuerte viene con ARC, retener era predeterminado antes de ARC
abdullahselek
56

Atómico:

Atomic garantiza que el acceso a la propiedad se realizará de manera atómica. Por ejemplo, siempre devuelve objetos completamente inicializados, cualquier get / set de una propiedad en un hilo debe completarse antes de que otro pueda acceder a él.

Si imagina que la siguiente función ocurre en dos hilos a la vez, puede ver por qué los resultados no serían bonitos.

-(void) setName:(NSString*)string
{
  if (name)
  {
    [name release]; 
    // what happens if the second thread jumps in now !?
    // name may be deleted, but our 'name' variable is still set!
    name = nil;
  }

  ...
}

Pros: el retorno de objetos totalmente inicializados cada vez es la mejor opción en caso de subprocesos múltiples.

Contras: impacto en el rendimiento, hace que la ejecución sea un poco más lenta

No atómico:

A diferencia de Atomic, no garantiza el retorno de objetos completamente inicializados cada vez.

Pros: ejecución extremadamente rápida.

Contras: posibilidades de valor de basura en caso de subprocesos múltiples.

Andrew Grant
fuente
55
Ese comentario no tiene mucho sentido. ¿Puedes aclarar? Si observa ejemplos en el sitio de Apple, la palabra clave atómica se sincroniza en el objeto mientras actualiza sus propiedades.
Andrew Grant
52

La respuesta más fácil primero: no hay diferencia entre sus dos segundos ejemplos. Por defecto, los accesores de propiedad son atómicos.

Los accesores atómicos en un entorno sin recolección de basura (es decir, cuando se usa retención / liberación / liberación automática) usarán un bloqueo para garantizar que otro hilo no interfiera con la configuración / obtención correcta del valor.

Consulte la sección " Rendimiento y subprocesos " de la documentación de Objective-C 2.0 de Apple para obtener más información y otras consideraciones al crear aplicaciones de subprocesos múltiples.

Jay O'Conor
fuente
8
Dos razones. En primer lugar, para el código sintetizado genera más rápido (pero no código seguro para subprocesos). En segundo lugar, si está escribiendo accesores de clientes que no son atómicos, le permite anotar para cualquier usuario futuro que el código no es atómico cuando está leyendo su interfaz, sin hacer que se implemente.
Louis Gerbarg
31

Atómico significa que solo un hilo accede a la variable (tipo estático). Atomic es seguro para subprocesos, pero es lento.

No atómico significa que múltiples hilos acceden a la variable (tipo dinámico). Nonatomic no es seguro para subprocesos, pero es rápido.

IOS Rocks
fuente
14

Atomic es seguro para subprocesos , es lento y asegura (no está garantizado) que solo se proporciona el valor bloqueado sin importar cuántos subprocesos intenten acceder en la misma zona. Cuando se usa atomic, un fragmento de código escrito dentro de esta función se convierte en parte de la sección crítica, a la que solo se puede ejecutar un subproceso a la vez.

Solo asegura la seguridad del hilo; No garantiza eso. Lo que quiero decir es que contratas a un conductor experto para tu auto, aún así no garantiza que el auto no tenga un accidente. Sin embargo, la probabilidad sigue siendo la más mínima.

Atómico: no se puede descomponer, por lo que se espera el resultado. Con no atómico: cuando otro subproceso accede a la zona de memoria, puede modificarlo, por lo que el resultado es inesperado.

Code Talk:

Atomic hace que getter y setter de la propiedad sean seguros. por ejemplo si has escrito:

self.myProperty = value;

es seguro para hilos.

[myArray addObject:@"Abc"] 

NO es seguro para hilos.


fuente
No sé cómo viene el último párrafo, pero es simplemente incorrecto, no existe tal cosa como "copia privada".
pico
13

No existe esa palabra clave "atómica"

@property(atomic, retain) UITextField *userName;

Podemos usar lo anterior como

@property(retain) UITextField *userName;

Consulte la pregunta sobre desbordamiento de pila. Tengo problemas si uso @property (atomic, retener) NSString * myString .

Deepak
fuente
10
"Existe dicha palabra clave". Que la palabra clave no sea necesaria de manera predeterminada e incluso que el valor predeterminado no significa que la palabra clave no existe.
Matthijn
44
Esto es incorrecto. La palabra clave existe. Esta respuesta es engañosa, y me gustaría alentarla.
Sethfri
12

atómico (predeterminado)

Atómico es el valor predeterminado: si no escribe nada, su propiedad es atómica. Se garantiza una propiedad atómica que si intenta leer de ella, obtendrá un valor válido. No ofrece ninguna garantía sobre cuál podría ser ese valor, pero obtendrá buenos datos, no solo la memoria basura. Lo que esto le permite hacer es que si tiene múltiples hilos o múltiples procesos apuntando a una sola variable, un hilo puede leer y otro hilo puede escribir. Si golpean al mismo tiempo, se garantiza que el hilo del lector obtendrá uno de los dos valores: antes del cambio o después del cambio. Lo que atomic no le ofrece es ningún tipo de garantía sobre cuáles de esos valores podría obtener. Atomic se confunde realmente con ser seguro para subprocesos, y eso no es correcto. Debe garantizar la seguridad de su hilo de otras maneras.

no atómico

Por otro lado, no atómico, como probablemente puedas adivinar, solo significa "no hagas esas cosas atómicas". Lo que pierde es esa garantía de que siempre recuperará algo. Si intenta leer en medio de una escritura, podría recuperar datos basura. Pero, por otro lado, vas un poco más rápido. Debido a que las propiedades atómicas tienen que hacer algo de magia para garantizar que obtendrá un valor, son un poco más lentas. Si es una propiedad a la que está accediendo mucho, es posible que desee desplegar a no atómico para asegurarse de no incurrir en esa penalización de velocidad.

Ver más aquí: https://realm.io/news/tmi-objective-c-property-attributes/

Protón
fuente
11

El valor predeterminado esatomic , esto significa que le cuesta rendimiento cada vez que usa la propiedad, pero es seguro para subprocesos. Lo que hace Objective-C es establecer un bloqueo, por lo que solo el hilo real puede acceder a la variable, siempre que se ejecute el setter / getter.

Ejemplo con MRC de una propiedad con un ivar _ interno:

[_internal lock]; //lock
id result = [[value retain] autorelease];
[_internal unlock];
return result;

Entonces estos dos últimos son iguales:

@property(atomic, retain) UITextField *userName;

@property(retain) UITextField *userName; // defaults to atomic

Por otro lado, no nonatomicagrega nada a su código. Por lo tanto, solo es seguro para subprocesos si codifica usted mismo el mecanismo de seguridad.

@property(nonatomic, retain) UITextField *userName;

Las palabras clave no tienen que escribirse como primer atributo de propiedad.

No olvide que esto no significa que la propiedad en su conjunto sea segura para subprocesos. Solo la llamada al método del setter / getter es. Pero si usa un setter y luego un getter al mismo tiempo con 2 hilos diferentes, ¡podría romperse también!

Binario
fuente
10

Antes de comenzar: debe saber que cada objeto en la memoria debe ser desasignado de la memoria para que ocurra un nuevo escritor. No puedes simplemente escribir encima de algo como lo haces en papel. Usted debe borrar primero (dealloc) y luego se puede escribir en él. Si en el momento en que se borra (o se hace a medias) y aún no se ha escrito nada (o se ha escrito a medias) e intenta leerlo, ¡podría ser muy problemático! La ayuda atómica y no atómica lo ayuda a tratar este problema de diferentes maneras.

Primero lea esta pregunta y luego lea la respuesta de Bbum . Además, luego lea mi resumen.


atomic SIEMPRE garantizará

  • Si dos personas diferentes quieren leer y escribir al mismo tiempo, ¡tu papel no se quemará! -> Tu aplicación nunca se bloqueará, incluso en condiciones de carrera.
  • Si una persona está tratando de escribir y solo ha escrito 4 de las 8 letras para escribir, entonces no se puede leer en el medio, la lectura solo se puede hacer cuando se escriben las 8 letras -> No sucederá lectura (get) en 'un hilo que todavía está escribiendo', es decir, si hay que escribir de 8 bytes a bytes y solo se escriben 4 bytes, hasta ese momento, no se le permite leer de él. Pero como dije que no se bloqueará, leería el valor de un objeto lanzado automáticamente .
  • Si antes de escribir ha borrado lo que se escribió anteriormente en papel y luego alguien quiere leer, aún puede leer. ¿Cómo? Leerá algo similar a la papelera de Mac OS (ya que la papelera aún no se ha borrado al 100% ... está en un limbo) ---> Si ThreadA es para leer mientras ThreadB ya se ha desasignado para escribir, obtendrá un valor del valor final completamente escrito por ThreadB u obtener algo del grupo de liberación automática.

Retener recuentos es la forma en que se gestiona la memoria en Objective-C. Cuando crea un objeto, tiene una cuenta de retención de 1. Cuando envía un mensaje de retención a un objeto, su cuenta de retención se incrementa en 1. Cuando envía un mensaje de liberación a un objeto, su cuenta de retención se reduce en 1. Cuando envía un objeto a un mensaje de liberación automática , su recuento de retención se reduce en 1 en algún momento en el futuro. Si el recuento de retención de un objeto se reduce a 0, se desasigna.

  • Atomic no garantiza la seguridad del hilo, aunque es útil para lograr la seguridad del hilo. La seguridad de subprocesos depende de cómo escriba su código / de qué fila de subprocesos está leyendo / escribiendo. Solo garantiza el subprocesamiento múltiple no bloqueable.

¡¿Qué?! Son multihilo y seguridad de hilo diferentes ?

Si. Multiproceso significa: varios subprocesos pueden leer un dato compartido al mismo tiempo y no nos bloquearemos, sin embargo, no garantiza que no esté leyendo desde un valor no publicado automáticamente. Con la seguridad de subprocesos, se garantiza que lo que lee no se libera automáticamente. La razón por la que no hacemos que todo sea atómico por defecto es que hay un costo de rendimiento y para la mayoría de las cosas realmente no se necesita seguridad en los hilos. Algunas partes de nuestro código lo necesitan y para esas pocas partes, tenemos que escribir nuestro código de manera segura para subprocesos utilizando bloqueos, mutex o sincronización.


nonatomic

  • Dado que no existe una Papelera para Mac OS, a nadie le importa si siempre obtienes un valor (<- Esto podría provocar un bloqueo), y a nadie le importa si alguien intenta leer la mitad de tu escritura (aunque escribir a mitad de camino en la memoria es muy diferente de escribir a mitad de camino en papel, en la memoria podría darte un valor estúpido loco de antes, mientras que en papel solo ves la mitad de lo que se ha escrito) -> No garantiza que no se bloquee, porque No utiliza el mecanismo de liberación automática.
  • ¡No garantiza que se lean todos los valores escritos!
  • Es más rápido que atómico

En general son diferentes en 2 aspectos:

  • Falla o no por tener o no tener un grupo de liberación automática.

  • Permitir que se lea justo en el medio de un "valor de escritura o valor vacío aún no terminado" o no permitir y solo permitir leer cuando el valor está completamente escrito.

Miel
fuente
9

Si está utilizando su propiedad en código multiproceso, entonces podrá ver la diferencia entre los atributos atómicos y no atómicos. Nonatomic es más rápido que atomic y atomic es seguro para subprocesos, no no atómico.

Vijayendra Tripathi ya ha dado un ejemplo para un entorno multiproceso.

Ankul Gaur
fuente
9
  • -Atomic significa que solo un hilo accede a la variable (tipo estático).
  • -Atomic es seguro para subprocesos.
  • -pero es lento en rendimiento

Cómo declarar:

Como atómico es el predeterminado, entonces

@property (retain) NSString *name;

Y en el archivo de implementación

self.name = @"sourov";

Supongamos que una tarea relacionada con tres propiedades son

 @property (retain) NSString *name;
 @property (retain) NSString *A;
 @property (retain) NSString *B;
 self.name = @"sourov";

Todas las propiedades funcionan en paralelo (como asincrónicamente).

Si llamas "nombre" desde el hilo A ,

Y

Al mismo tiempo si llamas

[self setName:@"Datta"]

del hilo B ,

Ahora si la propiedad * name no es atómica, entonces

  • Devolverá el valor "Datta" para A
  • Devolverá el valor "Datta" para B

Es por eso que no atómico se llama hilo inseguro, pero es rápido en rendimiento debido a la ejecución paralela

Ahora si la propiedad * name es atómica

  • Asegurará el valor "Sourov" para A
  • Entonces devolverá el valor "Datta" para B

Es por eso que atomic se llama thread Safe y por eso se llama read-write safe

Tal operación de situación se realizará en serie. Y lento en rendimiento

- No atómico significa acceso múltiple a la variable (tipo dinámico).

- No atómico es un hilo inseguro.

- pero es rápido en rendimiento

-Nonatomic NO es un comportamiento predeterminado, debemos agregar una palabra clave no atómica en el atributo de propiedad.

Para In Swift Confirmando que las propiedades Swift son no atómicas en el sentido ObjC. Una razón es para pensar si la atomicidad por propiedad es suficiente para sus necesidades.

Referencia: https://forums.developer.apple.com/thread/25642

Para obtener más información, visite el sitio web http://rdcworld-iphone.blogspot.in/2012/12/variable-property-attributes-or.html

Shourob Datta
fuente
44
Como muchos otros muchos han dicho, ¡ NOatomic es seguro para subprocesos! Es más resistente a los problemas de hilo, pero no es seguro para hilos. Simplemente asegura que obtendrá un valor completo, también conocido como un valor "correcto" (nivel binario), pero de ninguna manera se asegurará de que sea el valor actual y "correcto" para la lógica de su negocio (podría ser un valor pasado y inválido por su lógica).
Alejandro Iván
6

Atomicidad atómica (predeterminado)

Atómico es el valor predeterminado: si no escribe nada, su propiedad es atómica. Se garantiza una propiedad atómica que si intenta leer de ella, obtendrá un valor válido. No ofrece ninguna garantía sobre cuál podría ser ese valor, pero obtendrá buenos datos, no solo la memoria basura. Lo que esto le permite hacer es que si tiene múltiples hilos o múltiples procesos apuntando a una sola variable, un hilo puede leer y otro hilo puede escribir. Si golpean al mismo tiempo, se garantiza que el hilo del lector obtendrá uno de los dos valores: antes del cambio o después del cambio. Lo que atomic no le ofrece es ningún tipo de garantía sobre cuáles de esos valores podría obtener. Atomic se confunde realmente con ser seguro para subprocesos, y eso no es correcto. Debe garantizar la seguridad de su hilo de otras maneras.

no atómico

Por otro lado, no atómico, como probablemente puedas adivinar, solo significa "no hagas esas cosas atómicas". Lo que pierde es esa garantía de que siempre recuperará algo. Si intenta leer en medio de una escritura, podría recuperar datos basura. Pero, por otro lado, vas un poco más rápido. Debido a que las propiedades atómicas tienen que hacer algo de magia para garantizar que obtendrá un valor, son un poco más lentas. Si es una propiedad a la que está accediendo mucho, es posible que desee desplegar a no atómico para asegurarse de no incurrir en esa penalización de velocidad. Acceso

cortesía https://academy.realm.io/posts/tmi-objective-c-property-attributes/

Los atributos de propiedad de atomicidad (atómica y no atómica) no se reflejan en la declaración de propiedad de Swift correspondiente, pero las garantías de atomicidad de la implementación de Objective-C aún se mantienen cuando se accede a la propiedad importada desde Swift.

Entonces, si define una propiedad atómica en Objective-C, permanecerá atómica cuando Swift la use.

cortesía https://medium.com/@YogevSitton/atomic-vs-non-atomic-properties-crash-course-d11c23f4366c

Suraj K Thomas
fuente
5

La propiedad atómica asegura retener un valor completamente inicializado independientemente de cuántos hilos estén haciendo getter & setter en él.

La propiedad no atómica especifica que los accesos sintetizados simplemente establecen o devuelven un valor directamente, sin garantías sobre lo que sucede si se accede a ese mismo valor simultáneamente desde diferentes hilos.

Laxman Sahni
fuente
3

Atómico significa que solo un subproceso puede acceder a la variable a la vez (tipo estático). Atomic es seguro para subprocesos, pero es lento.

No atómico significa que varios subprocesos pueden acceder a la variable al mismo tiempo (tipo dinámico). No atómico no es seguro para subprocesos, pero es rápido.

Kemo
fuente
1

Si está utilizando atomic, significa que el hilo será seguro y de solo lectura. Si está utilizando no atómico, significa que los múltiples hilos acceden a la variable y no es seguro, pero se ejecuta rápidamente, se realizan operaciones de lectura y escritura; Este es un tipo dinámico.

Preetha
fuente
1

La verdad es que usan el bloqueo de giro para implementar la propiedad atómica. El código de la siguiente manera:

 static inline void reallySetProperty(id self, SEL _cmd, id newValue, 
      ptrdiff_t offset, bool atomic, bool copy, bool mutableCopy) 
    {
        id oldValue;
        id *slot = (id*) ((char*)self + offset);

        if (copy) {
            newValue = [newValue copyWithZone:NULL];
        } else if (mutableCopy) {
            newValue = [newValue mutableCopyWithZone:NULL];
        } else {
            if (*slot == newValue) return;
            newValue = objc_retain(newValue);
        }

        if (!atomic) {
            oldValue = *slot;
            *slot = newValue;
        } else {
            spin_lock_t *slotlock = &PropertyLocks[GOODHASH(slot)];
            _spin_lock(slotlock);
            oldValue = *slot;
            *slot = newValue;        
            _spin_unlock(slotlock);
        }

        objc_release(oldValue);
    }
Pablo
fuente
0

Para simplificar toda la confusión, comprendamos el bloqueo de mutex.

El bloqueo Mutex, según el nombre, bloquea la mutabilidad del objeto. Entonces, si una clase accede al objeto, ninguna otra clase puede acceder al mismo objeto.

En iOS, @sychronisetambién proporciona el bloqueo de mutex. Ahora sirve en modo FIFO y garantiza que el flujo no se vea afectado por dos clases que comparten la misma instancia. Sin embargo, si la tarea está en el subproceso principal, evite acceder al objeto utilizando propiedades atómicas, ya que puede contener su interfaz de usuario y degradar el rendimiento.

Suryanarayan Sahu
fuente
-1

Atómico: garantice la seguridad del hilo bloqueándolo con NSLOCK.

No atómico: no garantiza la seguridad del hilo ya que no hay un mecanismo de bloqueo del hilo.

satisharyan
fuente
-1

Propiedades atómicas : cuando una variable asignada con propiedad atómica significa que solo tiene acceso a un subproceso y será seguro para los subprocesos y tendrá una buena perspectiva de rendimiento, tendrá un comportamiento predeterminado.

Propiedades no atómicas : cuando una variable asignada con propiedad atómica significa que tiene acceso a múltiples subprocesos y no será segura para subprocesos y será lenta en la perspectiva de rendimiento, tendrá un comportamiento predeterminado y cuando dos subprocesos diferentes desean acceder a la variable al mismo tiempo dará resultados inesperados

ashish.surana
fuente