Qual é a diferença entre os atributos atômicos e não atômicos?

Respostas:

1761

Os dois últimos são idênticos; "atomic" é o comportamento padrão ( observe que na verdade não é uma palavra-chave; é especificada apenas pela ausência denonatomic - atomicfoi adicionada como uma palavra-chave nas versões recentes do llvm / clang).

Supondo que você esteja @sintetizando as implementações do método, atômico x não atômico altera o código gerado. Se você estiver escrevendo seu próprio setter / getters, atômico / não atômico / reter / atribuir / copiar são meramente consultivos. (Nota: @synthesize agora é o comportamento padrão nas versões recentes do LLVM. Também não há necessidade de declarar variáveis ​​de instância; elas também serão sintetizadas automaticamente e terão um _nome acrescentado ao seu nome para impedir o acesso direto acidental).

Com "atômico", o setter / getter sintetizado garantirá que um valor inteiro seja sempre retornado do getter ou definido pelo setter, independentemente da atividade do setter em qualquer outro encadeamento. Ou seja, se o encadeamento A estiver no meio do getter, enquanto o encadeamento B chamar o setter, um valor viável real - um objeto liberado automaticamente, provavelmente - será retornado ao chamador em A.

Em nonatomic, essas garantias não são feitas. Assim, nonatomicé consideravelmente mais rápido que "atômico".

O que "atômico" não faz é garantir a segurança do encadeamento. Se o encadeamento A estiver chamando o getter simultaneamente com o encadeamento B e C, chamando o setter com valores diferentes, o encadeamento A poderá receber qualquer um dos três valores retornados - o anterior a qualquer chamador chamado ou qualquer um dos valores passados ​​para o setter em B e C. Da mesma forma, o objeto pode acabar com o valor de B ou C, não há como saber.

Garantir a integridade dos dados - um dos principais desafios da programação multithread - é alcançado por outros meios.

Adicionando a isso:

atomicity de uma única propriedade também não pode garantir a segurança do encadeamento quando várias propriedades dependentes estão em jogo.

Considerar:

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

Nesse caso, o segmento A pode renomear o objeto chamando setFirstName:e depois chamando setLastName:. Enquanto isso, o segmento B pode chamar fullNameentre as duas chamadas do segmento A e receberá o novo primeiro nome juntamente com o sobrenome antigo.

Para resolver isso, você precisa de um modelo transacional . Ou seja, algum outro tipo de sincronização e / ou exclusão que permita excluir o acesso fullNameenquanto as propriedades dependentes estiverem sendo atualizadas.

bbum
fonte
21
Dado que qualquer código de thread-safe fará seu próprio bloqueio, etc., quando você deseja usar acessadores de propriedades atômicas? Estou tendo problemas para pensar em um bom exemplo.
Daniel Dickison
8
@bbum Faz sentido. Gosto do seu comentário para outra resposta de que a segurança de threads é mais uma preocupação no nível do modelo. De uma definição de segurança de encadeamento IBM: ibm.co/yTEbjY "Se uma classe for implementada corretamente, o que é outra maneira de dizer que está em conformidade com sua especificação, nenhuma sequência de operações (leituras ou gravações de campos públicos e chamadas para métodos públicos) nos objetos dessa classe, é possível colocar o objeto em um estado inválido, observar que o objeto esteja em um estado inválido ou violar qualquer um dos invariantes, pré-condições ou pós-condições da classe. "
Ben Flynn
6
Aqui está um exemplo semelhante ao @StevenKramer 's: Eu tenho um @property NSArray* astronomicalEvents;que lista os dados que eu quero exibir na interface do usuário. Quando o aplicativo inicia o ponteiro aponta para uma matriz vazia, o aplicativo extrai dados da Web. Quando a solicitação da Web é concluída (em um encadeamento diferente), o aplicativo cria uma nova matriz e define atomicamente a propriedade com um novo valor de ponteiro. É seguro para threads e eu não precisei escrever nenhum código de bloqueio, a menos que esteja faltando alguma coisa. Parece muito útil para mim.
21813 bugloaf
10
@HotLicks Outro divertido; em certas arquiteturas (não me lembro qual), os valores de 64 bits passados ​​como argumento podem ser passados ​​metade em um registrador e metade na pilha. atomicimpede leituras de meio valor de encadeamento cruzado. (Isso foi um erro divertido de rastrear.)
bbum
8
@congliu O segmento A retorna um objeto sem retain/autoreleasedança. O segmento B libera o objeto. O segmento A vai crescer . atomicgarante que o segmento A tenha uma referência forte (uma contagem de retenção +1) para o valor de retorno.
bbum
360

Isso é explicado na documentação da Apple , mas abaixo estão alguns exemplos do que realmente está acontecendo.

Observe que não há palavra-chave "atômica", se você não especificar "não atômico", a propriedade será atômica, mas especificar "atômico" explicitamente resultará em um erro.

Se você não especificar "não atômico", a propriedade será atômica, mas ainda poderá especificar "atômico" explicitamente nas versões recentes, se desejar.

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

- (UITextField *) userName {
    return userName;
}

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

Agora, a variante atômica é um pouco mais 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_;
    }
}

Basicamente, a versão atômica precisa ser bloqueada para garantir a segurança do encadeamento e também está aumentando a contagem de referências no objeto (e a contagem de autorelease para equilibrá-lo) para garantir a existência do objeto para o chamador, caso contrário, existe é uma condição de corrida em potencial se outro encadeamento estiver definindo o valor, fazendo com que a contagem de referências caia para 0.

Na verdade, existe um grande número de variantes diferentes de como essas coisas funcionam, dependendo se as propriedades são valores ou objetos escalares, e como reter, copiar, somente leitura, não atômico, etc. Em geral, os sintetizadores de propriedades apenas sabem como fazer a "coisa certa" para todas as combinações.

Louis Gerbarg
fonte
8
@Louis Gerbarg: Eu acredito que a sua versão do (reter nonatomic,) setter não funcionará corretamente se você tentar atribuir o mesmo objeto (ou seja: username == nome de usuário_)
Florin
5
Seu código é um pouco enganador; não garantia sobre quais getters / setters atômicos são sincronizados. Criticamente, @property (assign) id delegate;não é sincronizado em nada (iOS SDK GCC 4.2 ARM -Os), o que significa que há uma corrida entre [self.delegate delegateMethod:self];e foo.delegate = nil; self.foo = nil; [super dealloc];. Consulte stackoverflow.com/questions/917884/…
tc.
@fyolnish Eu não tenho certeza do que _val/ valsão, mas não, não realmente. O getter para uma propriedade atômica copy/ retainprecisa garantir que ele não retorne um objeto cuja refcount se torne zero devido ao setter ser chamado em outro encadeamento, o que significa essencialmente que ele precisa ler o ivar, retê-lo e garantir que o setter não tenha sobrescrito e liberado e liberte-o automaticamente para equilibrar a retenção. Isso significa essencialmente tanto o getter e setter tem que usar um bloqueio (se o layout de memória foi fixado deve ser factível com instruções CAS2; infelizmente -retainé uma chamada de método).
tc.
@tc Já faz um bom tempo, mas o que eu pretendia escrever era provavelmente o seguinte: gist.github.com/fjolnir/5d96b3272c6255f6baae Mas sim, é possível que o valor antigo seja lido por um leitor antes do setFoo: retorna e liberado antes do leitor devolve. Mas talvez se o setter usasse -autorelease em vez de -release, isso resolveria isso.
Fjölnir 11/12/13
@fyolnish Infelizmente, não: isso libera automaticamente o thread do setter, enquanto ele precisa ser liberado automaticamente no thread do getter. Também parece que há uma chance (pequena) de ficar sem pilha porque você está usando recursão.
tc.
170

Atomic

  • é o comportamento padrão
  • garantirá que o processo atual seja concluído pela CPU, antes que outro processo acesse a variável
  • não é rápido, pois garante que o processo seja totalmente concluído

Não atômico

  • NÃO é o comportamento padrão
  • mais rápido (para código sintetizado, ou seja, para variáveis ​​criadas usando @property e @synthesize)
  • não é seguro para threads
  • pode resultar em comportamento inesperado, quando dois processos diferentes acessam a mesma variável ao mesmo tempo
raw3d
fonte
137

A melhor maneira de entender a diferença é usando o exemplo a seguir.

Suponha que exista uma propriedade de string atômica chamada "name" e, se você ligar [self setName:@"A"]do thread A, [self setName:@"B"]do thread B e [self name]do thread C, todas as operações em threads diferentes serão executadas serialmente, o que significa que se um thread estiver executando um setter ou getter, outros threads aguardam.

Isso torna a propriedade "nome" de leitura / gravação segura, mas se outro encadeamento, D, chamar [name release]simultaneamente, essa operação poderá causar uma falha, porque não há nenhuma chamada de setter / getter envolvida aqui. O que significa que um objeto é seguro para leitura / gravação (ATOMIC), mas não é seguro para threads, pois outros threads podem enviar simultaneamente qualquer tipo de mensagem para o objeto. O desenvolvedor deve garantir a segurança do thread para esses objetos.

Se a propriedade "nome" não for atômica, todos os threads no exemplo acima - A, B, C e D serão executados simultaneamente, produzindo qualquer resultado imprevisível. No caso de atômico, um de A, B ou C será executado primeiro, mas D ainda pode ser executado em paralelo.

Vijayendra
fonte
116

A sintaxe e a semântica já estão bem definidas por outras excelentes respostas a essa pergunta. Como a execução e o desempenho não são bem detalhados, adicionarei minha resposta.

Qual é a diferença funcional entre esses 3?

Eu sempre considerei atômica um padrão bastante curioso. No nível de abstração em que trabalhamos, o uso de propriedades atômicas para uma classe como veículo para atingir 100% de segurança é um caso de esquina. Para programas multithread verdadeiramente corretos, a intervenção do programador é quase certamente um requisito. Enquanto isso, as características de desempenho e a execução ainda não foram detalhadas em profundidade. Tendo escrito alguns programas altamente multithread ao longo dos anos, eu estava declarando minhas propriedades nonatomico tempo todo porque o atômico não era sensível a nenhum propósito. Durante a discussão dos detalhes das propriedades atômicas e não atômicas, nesta pergunta , fiz alguns perfis e encontrei alguns resultados curiosos.

Execução

Está bem. A primeira coisa que gostaria de esclarecer é que a implementação de bloqueio é definida e abstraída. Louis usa @synchronized(self)em seu exemplo - eu vi isso como uma fonte comum de confusão. A implementação não é realmente usada @synchronized(self); ele usa bloqueios de rotação no nível do objeto . A ilustração de Louis é boa para uma ilustração de alto nível usando construções com as quais todos estamos familiarizados, mas é importante saber que ela não é usada @synchronized(self).

Outra diferença é que as propriedades atômicas reterão / liberarão o ciclo de seus objetos no getter.

atuação

Aqui está a parte interessante: O desempenho usando acessos de propriedades atômicas em casos não contestados (por exemplo, thread único) pode ser realmente muito rápido em alguns casos. Em casos abaixo do ideal, o uso de acessos atômicos pode custar mais de 20 vezes a sobrecarga de nonatomic. Enquanto o caso contestado usando 7 threads foi 44 vezes mais lento para a estrutura de três bytes (2,2 GHz Core i7 Quad Core, x86_64). A estrutura de três bytes é um exemplo de uma propriedade muito lenta.

Nota lateral interessante: os acessadores definidos pelo usuário da estrutura de três bytes foram 52 vezes mais rápidos que os acessadores atômicos sintetizados; ou 84% da velocidade dos acessadores não atômicos sintetizados.

Objetos em casos contestados também podem exceder 50 vezes.

Devido ao número de otimizações e variações nas implementações, é bastante difícil medir os impactos do mundo real nesses contextos. Você pode ouvir algo como "Confie, a menos que você crie um perfil e ache que é um problema". Devido ao nível de abstração, é realmente muito difícil medir o impacto real. A coleta de custos reais de perfis pode consumir muito tempo e, devido a abstrações, ser bastante imprecisa. Além disso, ARC vs MRC pode fazer uma grande diferença.

Então, vamos voltar atrás, sem focar na implementação de acessos a propriedades, incluiremos os suspeitos do costume objc_msgSende examinaremos alguns resultados de alto nível do mundo real para muitas chamadas para um NSStringgetter em casos não contestados (valores em segundos):

  • MRC não atômico getters implementados manualmente: 2
  • MRC não atômico getter sintetizado: 7
  • MRC atômico | getter sintetizado: 47
  • ARC não atômico getter sintetizado: 38 (nota: o ARC está adicionando um número de ref de ciclo aqui)
  • ARC atômico | getter sintetizado: 47

Como você provavelmente já adivinhou, a atividade de contagem de referência / ciclismo é um colaborador significativo dos atômicos e do ARC. Você também veria diferenças maiores nos casos contestados.

Embora eu preste muita atenção ao desempenho, ainda digo Semantics First! . Enquanto isso, o desempenho é uma baixa prioridade para muitos projetos. No entanto, conhecer os detalhes da execução e os custos das tecnologias usadas certamente não prejudica. Você deve usar a tecnologia certa para suas necessidades, propósitos e habilidades. Espero que isso poupe algumas horas de comparações e ajude você a tomar uma decisão melhor informada ao criar seus programas.

justin
fonte
MRC atômico | getter sintetizado: 47 ARC | atômico | getter sintetizado: 47 O que os torna iguais? O ARC não deveria ter mais despesas gerais?
SDEZero 27/08
2
Portanto, se as propriedades atômicas são ruins, elas são padrão. Para aumentar o código padrão?
Kunal Balani
@ LearnCocos2D Acabei de testar o 10.8.5 na mesma máquina, visando o 10.8, para o caso não contestado de thread único com um NSStringque não é imortal: -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%- os resultados são um pouco diferentes hoje. Eu não estava fazendo nenhuma @synchronizedcomparação. @synchronizedé semanticamente diferente e não considero uma boa ferramenta se você tiver programas concorrentes não triviais. se você precisar de velocidade, evite @synchronized.
justin
você tem esse teste online em algum lugar? Eu continuo adicionando o meu aqui: github.com/LearnCocos2D/LearnCocos2D/tree/master/…
LearnCocos2D
@ LearnCocos2D eu não os preparei para consumo humano, desculpe.
justin
95

Atômica = segurança da linha

Não atômico = Sem segurança de thread

Segurança da linha:

As variáveis ​​de instância são seguras para encadeamento se elas se comportarem corretamente quando acessadas de vários encadeamentos, independentemente do agendamento ou intercalação da execução desses encadeamentos pelo ambiente de tempo de execução, e sem sincronização adicional ou outra coordenação por parte do código de chamada.

No nosso contexto:

Se um encadeamento alterar o valor da instância, o valor alterado estará disponível para todos os encadeamentos, e apenas um encadeamento poderá alterar o valor de cada vez.

Onde usar atomic:

se a variável de instância for acessada em um ambiente multithread.

Implicação de atomic:

Não é tão rápido quanto nonatomicporque nonatomicnão requer nenhum trabalho de vigilância sobre isso no tempo de execução.

Onde usar nonatomic:

Se a variável de instância não for alterada por vários threads, você poderá usá-la. Melhora o desempenho.

Durai Amuthan.H
fonte
3
Tudo o que você diz aqui está correto, mas a última frase está essencialmente "errada", Dura, para a programação de hoje. É realmente inconcebível que você se preocupe em tentar "melhorar o desempenho" dessa maneira. (Quero dizer, antes de você chegar a menos de cinquenta anos, você "não usaria o ARC", "não usaria o NSString porque é lento!" E assim por diante.) Para dar um exemplo extremo, seria como dizer "equipe, não coloque nenhum comentário no código, pois isso nos atrasa ". Não existe um pipeline de desenvolvimento realista no qual você queira obter ganhos de desempenho teóricos (inexistentes) por falta de confiabilidade.
Fattie
3
@JoeBlow é um fato que você pode verificá-lo aqui developer.apple.com/library/mac/documentation/Cocoa/Conceptual/…
Durai Amuthan
1
Durai, FWIW, esse link contradiz diretamente sua tese de "Atomic = thread safety". No documento, a Apple diz explicitamente: "Atomicidade de propriedade não é sinônimo de segurança de thread de um objeto". Na prática, atômica raramente é suficiente para garantir a segurança do encadeamento.
Rob
69

Encontrei uma explicação bastante bem posta das propriedades atômicas e não atômicas aqui . Aqui está um texto relevante do mesmo:

'atômico' significa que não pode ser decomposto. Em termos de SO / programação, uma chamada de função atômica é aquela que não pode ser interrompida - a função inteira deve ser executada e não trocada para fora da CPU pela alternância de contexto usual do SO até sua conclusão. Apenas no caso de você não saber: como a CPU só pode fazer uma coisa de cada vez, o SO roda o acesso à CPU a todos os processos em execução em pequenos intervalos de tempo, para dar a ilusãode multitarefa. O agendador da CPU pode (e faz) interromper um processo a qualquer momento de sua execução - mesmo em uma chamada de função intermediária. Portanto, para ações como atualizar variáveis ​​de contador compartilhadas em que dois processos podem tentar atualizar a variável ao mesmo tempo, elas devem ser executadas 'atomicamente', ou seja, cada ação de atualização deve terminar completamente antes que qualquer outro processo possa ser trocado no CPU.

Portanto, eu acho que atômico neste caso significa que os métodos do leitor de atributos não podem ser interrompidos - o que significa que as variáveis ​​lidas pelo método não podem alterar seu valor no meio do caminho porque outra thread / chamada / função obtém trocado na CPU.

Como as atomicvariáveis ​​não podem ser interrompidas, o valor contido por elas a qualquer momento é (thread-lock) garantido como incorrupto , embora garantir que esse thread bloqueie o acesso a elas mais lentamente. non-atomicas variáveis, por outro lado, não oferecem essa garantia, mas oferecem o luxo de um acesso mais rápido. Para resumir, siga em frente non-atomicquando souber que suas variáveis ​​não serão acessadas por vários threads simultaneamente e acelere as coisas.

tipycalFlow
fonte
1
Link quebrado. ; (
Rob
Esse é o problema dos links :( felizmente, citei o texto relevante na minha resposta
tipycalFlow
67

Depois de ler tantos artigos, postar Stack Overflow e criar aplicativos de demonstração para verificar atributos de propriedades variáveis, decidi reunir todas as informações de atributos:

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

No artigo Atributos ou modificadores de propriedade variável no iOS, você pode encontrar todos os atributos mencionados acima e isso definitivamente o ajudará.

  1. atomic

    • atomic significa que apenas um encadeamento acessa a variável (tipo estático).
    • atomic é seguro para discussão.
    • Mas é lento no desempenho
    • atomic é o comportamento padrão
    • Os acessadores atômicos em um ambiente sem coleta de lixo (por exemplo, ao usar reter / liberar / liberação automática) usarão um bloqueio para garantir que outro encadeamento não interfira na configuração / obtenção correta do valor.
    • Na verdade, não é uma palavra-chave.

    Exemplo:

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

    • nonatomic significa que vários threads acessam a variável (tipo dinâmico).
    • nonatomic é inseguro para thread.
    • Mas é rápido no desempenho
    • nonatomicNÃO é um comportamento padrão. Precisamos adicionar a nonatomicpalavra - chave no atributo de propriedade.
    • Isso pode resultar em comportamento inesperado, quando dois processos diferentes (threads) acessam a mesma variável ao mesmo tempo.

    Exemplo:

        @property (nonatomic, retain) NSString *name;
    
        @synthesize name;
swiftBoy
fonte
Como atribuir e fortalecer / reter ambos é o padrão?
BangOperator 29/07
forte vem com ARC, conter era padrão antes ARC
abdullahselek
56

Atômica:

A Atomic garante que o acesso à propriedade será realizado de maneira atômica. Por exemplo, sempre retorna objetos totalmente inicializados, qualquer get / set de uma propriedade em um thread deve ser concluído antes que outro possa acessá-lo.

Se você imaginar a seguinte função ocorrendo em dois threads de uma só vez, poderá ver por que os resultados não seriam 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;
  }

  ...
}

Prós: O retorno de objetos totalmente inicializados sempre faz a melhor escolha em caso de multiencadeamento.

Contras: Desempenho atingido, torna a execução um pouco mais lenta

Não atômico:

Ao contrário do Atomic, ele não garante que o objeto totalmente inicializado retorne toda vez.

Prós: Execução extremamente rápida.

Contras: chances de valor do lixo em caso de multiencadeamento.

Andrew Grant
fonte
5
Esse comentário não faz muito sentido. Você pode esclarecer? Se você observar exemplos no site da Apple, a palavra-chave atômica será sincronizada no objeto enquanto atualiza suas propriedades.
Andrew Grant
52

Resposta mais fácil primeiro: não há diferença entre os dois segundos exemplos. Por padrão, os acessadores de propriedades são atômicos.

Os acessadores atômicos em um ambiente sem coleta de lixo (por exemplo, ao usar reter / liberar / liberação automática) usarão um bloqueio para garantir que outro encadeamento não interfira na configuração / obtenção correta do valor.

Consulte a seção " Desempenho e encadeamento " da documentação do Objective-C 2.0 da Apple para obter mais informações e outras considerações ao criar aplicativos multithread.

Jay O'Conor
fonte
8
Duas razões. Primeiro, para o código sintetizado, ele gera mais rápido (mas não é seguro). Segundo, se você está escrevendo acessadores de clientes que não são atômicos, permite anotar para qualquer usuário futuro que o código não é atômico quando eles estão lendo sua interface, sem torná-los implementados.
26264 Louis Gerbarg
31

Atômico significa que apenas um encadeamento acessa a variável (tipo estático). Atomic é seguro para threads, mas é lento.

Não atômico significa que vários threads acessam a variável (tipo dinâmico). Não atômico é thread inseguro, mas é rápido.

Rochas IOS
fonte
14

O Atomic é seguro para threads , é lento e garante (não garantido) que apenas o valor bloqueado seja fornecido, não importa quantos threads estejam tentando acessar na mesma zona. Ao usar atômica, um pedaço de código escrito dentro dessa função se torna a parte da seção crítica, na qual apenas um encadeamento pode ser executado por vez.

Ele apenas garante a segurança da linha; isso não garante isso. O que quero dizer é que você contrata um motorista experiente para o seu carro, mas isso não garante que o carro não sofra um acidente. No entanto, a probabilidade permanece a menor.

Atômico - não pode ser dividido, portanto, o resultado é esperado. Com não atômico - quando outro encadeamento acessa a zona de memória, ele pode modificá-lo, portanto o resultado é inesperado.

Discussão de código:

O Atomic torna seguro o getter e o setter do encadeamento de propriedades. por exemplo, se você escreveu:

self.myProperty = value;

é seguro para discussão.

[myArray addObject:@"Abc"] 

NÃO é seguro para threads.


fonte
Não sei como vem o último parágrafo, mas é simplesmente errado, não existe algo como "cópia privada".
peak
13

Não existe essa palavra-chave "atômica"

@property(atomic, retain) UITextField *userName;

Podemos usar o acima, como

@property(retain) UITextField *userName;

Consulte a pergunta sobre estouro de pilha . Estou tendo problemas se usar NSString * myString @property (atomic, reter) .

Deepak
fonte
10
"Existe tal palavra-chave", que a palavra-chave não é requerida por padrão e mesmo é o valor padrão não significa que a palavra-chave não existe.
Matthijn
4
Isto está incorreto. A palavra-chave existe. Esta resposta é enganosa, e eu encorajaria a derrubá-la.
Sethfri 20/05
12

atômico (padrão)

Atômico é o padrão: se você não digitar nada, sua propriedade é atômica. É garantida uma propriedade atômica que, se você tentar ler, receberá um valor válido. Ele não oferece nenhuma garantia sobre qual seria esse valor, mas você receberá bons dados, não apenas memória indesejada. O que isso permite que você faça é se você tiver vários threads ou vários processos apontando para uma única variável, um thread poderá ler e outro thread poderá gravar. Se eles atingirem ao mesmo tempo, é garantido que o encadeamento do leitor obtenha um dos dois valores: antes da alteração ou após a alteração. O que o atômico não oferece é qualquer tipo de garantia sobre quais desses valores você pode obter. Atomic é realmente comumente confundido com segurança de thread, e isso não está correto. Você precisa garantir a segurança da sua linha de outras maneiras.

não atômico

Por outro lado, não atômico, como você provavelmente pode adivinhar, significa apenas "não faça essas coisas atômicas". O que você perde é essa garantia de que você sempre recebe algo. Se você tentar ler no meio de uma gravação, poderá recuperar dados de lixo. Mas, por outro lado, você vai um pouco mais rápido. Como as propriedades atômicas precisam fazer alguma mágica para garantir que você recupere um valor, elas são um pouco mais lentas. Se for uma propriedade que você está acessando muito, pode usar a opção não-atômica para garantir que você não incorra nessa penalidade de velocidade.

Veja mais aqui: https://realm.io/news/tmi-objective-c-property-attributes/

Proton
fonte
11

O padrão é que atomicisso significa que lhe custa desempenho sempre que você usa a propriedade, mas é seguro para threads. O que o Objective-C faz é definir um bloqueio, para que apenas o encadeamento real possa acessar a variável, desde que o setter / getter seja executado.

Exemplo com o MRC de uma propriedade com um ivar _internal:

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

Portanto, esses dois últimos são os mesmos:

@property(atomic, retain) UITextField *userName;

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

Por outro lado, não nonatomicadiciona nada ao seu código. Portanto, é apenas thread-safe se você codificar o mecanismo de segurança.

@property(nonatomic, retain) UITextField *userName;

As palavras-chave não precisam ser escritas como o primeiro atributo de propriedade.

Não se esqueça, isso não significa que a propriedade como um todo seja segura para threads. Somente a chamada de método do setter / getter é. Mas se você usar um setter e depois um getter ao mesmo tempo com 2 threads diferentes, ele poderá ser quebrado também!

Binariano
fonte
10

Antes de começar: Você deve saber que todo objeto na memória precisa ser desalocado da memória para que um novo gravador aconteça. Você não pode simplesmente escrever em cima de algo como faz no papel. Você deve primeiro apagá-lo (desalocá-lo) e depois escrever nele. Se, no momento em que a exclusão estiver concluída (ou parcialmente concluída), e ainda nada tiver sido escrito (ou parcialmente escrito) e você tentar lê-la, isso poderá ser muito problemático! Atômica e não atômica ajudam a tratar esse problema de maneiras diferentes.

Primeiro leia esta pergunta e depois leia a resposta do Bbum . Além disso, leia meu resumo.


atomic garantirá SEMPRE

  • Se duas pessoas diferentes quiserem ler e escrever ao mesmo tempo, seu papel não será apenas queimado! -> Seu aplicativo nunca falha, mesmo em uma condição de corrida.
  • Se uma pessoa está tentando escrever e escreveu apenas 4 das 8 letras para escrever, então nenhuma pode ler no meio, a leitura só pode ser feita quando todas as 8 letras estiverem escritas -> Nenhuma leitura (obtenção) acontecerá em 'um encadeamento que ainda está gravando', ou seja, se houver 8 bytes em bytes a serem gravados e apenas 4 bytes forem gravados - até esse momento, você não poderá ler a partir dele. Mas como eu disse que não falhará, leria o valor de um objeto liberado automaticamente .
  • Se antes de escrita que você tenha apagado o que foi escrito anteriormente em papel e então alguém quer ler você pode ainda ler. Quão? Você estará lendo algo semelhante à lixeira do Mac OS (como a lixeira ainda não está 100% apagada ... está em um limbo) ---> Se o ThreadA for ler enquanto o ThreadB já estiver desalocado para escrever, você receberá um valor do valor final totalmente escrito por ThreadB ou obter algo do pool de liberação automática.

As contagens de retenção são a maneira pela qual a memória é gerenciada no Objective-C. Quando você cria um objeto, ele tem uma contagem de retenção de 1. Quando você envia uma mensagem de retenção a um objeto, sua contagem de retenção é incrementada em 1. Quando você envia uma mensagem de liberação a um objeto, sua contagem de retenção é diminuída em 1. Quando você envia enviar a um objeto uma mensagem de liberação automática , sua contagem de retenções é decrementada em 1 em algum momento no futuro. Se a contagem de retenção de um objeto for reduzida para 0, ela será desalocada.

  • O Atomic não garante a segurança da linha, embora seja útil para garantir a segurança da linha. A Segurança de Threads é relativa a como você escreve seu código / de qual fila de threads você está lendo / gravando. Garante apenas multithreading não crashable.

O que?! A segurança do multithreading e do thread é diferente?

Sim. Multithreading significa: vários threads podem ler um dado compartilhado ao mesmo tempo e não travaremos, mas isso não garante que você não esteja lendo de um valor não liberado automaticamente. Com a segurança de threads, é garantido que o que você lê não seja liberado automaticamente. O motivo de não tornarmos tudo atômico por padrão é que há um custo de desempenho e, para a maioria das coisas, realmente não precisamos de segurança de thread. Algumas partes do nosso código precisam dele e, para essas poucas partes, precisamos escrever nosso código de maneira segura, usando bloqueios, mutex ou sincronização.


nonatomic

  • Como não existe uma caixa de lixo do Mac OS, ninguém se importa se você sempre recebe um valor (<- isso pode levar a um acidente), e ninguém se importa se alguém tentar ler no meio da sua escrita (embora escrever a meio caminho na memória é muito diferente de escrever a meio caminho no papel, na memória isso pode lhe dar um valor estúpido e louco de antes, enquanto no papel você vê apenas metade do que foi escrito) -> Não garante que não caia, porque ele não usa o mecanismo de liberação automática.
  • Não garante que valores escritos completos sejam lidos!
  • É mais rápido que atômico

No geral, eles são diferentes em 2 aspectos:

  • Falhando ou não devido a ter ou não um pool de liberação automática.

  • Permitir a leitura no meio de uma 'gravação ainda não concluída ou valor vazio' ou não permitir e apenas permitir a leitura quando o valor estiver totalmente gravado.

Mel
fonte
9

Se você estiver usando sua propriedade no código multiencadeado, poderá ver a diferença entre atributos não atômicos e atômicos. Não atômico é mais rápido que atômico e atômico é seguro para threads, não é atômico.

Vijayendra Tripathi já deu um exemplo para um ambiente multiencadeado.

Ankul Gaur
fonte
9
  • -Atômico significa que apenas um thread acessa a variável (tipo estático).
  • -Atômico é seguro para threads.
  • -mas é lento no desempenho

Como declarar:

Como atômico é o padrão,

@property (retain) NSString *name;

E no arquivo de implementação

self.name = @"sourov";

Suponha que uma tarefa relacionada a três propriedades seja

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

Todas as propriedades funcionam paralelamente (como assincronamente).

Se você chamar "nome" do segmento A ,

E

Ao mesmo tempo, se você ligar

[self setName:@"Datta"]

da linha B ,

Agora, se a propriedade * name não for atômica ,

  • Ele retornará o valor "Datta" para A
  • Ele retornará o valor "Datta" para B

É por isso que o não atômico é chamado de thread inseguro. Mas, com desempenho rápido devido à execução paralela

Agora, se a propriedade * name for atômica

  • Isso garantirá o valor "Sourov" para A
  • Então ele retornará o valor "Datta" para B

É por isso que o atômico é chamado thread Safe e é por isso que é chamado read-write safe

Essa operação de situação será executada em série. E lento no desempenho

- Não atômico significa que vários threads acessam a variável (tipo dinâmico).

- Não atômico é um segmento inseguro.

- mas é rápido no desempenho

-Nonatômico NÃO é um comportamento padrão, precisamos adicionar palavras-chave não-atômicas no atributo de propriedade.

Para In Swift Confirmando que as propriedades Swift não são atômicas no sentido ObjC. Um dos motivos é você pensar se a atomicidade por propriedade é suficiente para suas necessidades.

Referência: https://forums.developer.apple.com/thread/25642

Para mais informações, visite o site http://rdcworld-iphone.blogspot.in/2012/12/variable-property-attributes-or.html

Shourob Datta
fonte
4
Como muitos outros muitos disseram, NÃOatomic é seguro para threads! É mais resistente a problemas de encadeamento, mas não é seguro. Ele apenas garante que você obterá um valor inteiro, também conhecido como valor "correto" (nível binário), mas de maneira alguma garantirá que seja o valor atual e "correto" para sua lógica de negócios (pode ser um valor passado e inválido pela sua lógica).
Alejandro Iván
6

Atomicidade atômica (padrão)

Atômico é o padrão: se você não digitar nada, sua propriedade é atômica. É garantida uma propriedade atômica que, se você tentar ler, receberá um valor válido. Ele não oferece nenhuma garantia sobre qual seria esse valor, mas você receberá bons dados, não apenas memória indesejada. O que isso permite que você faça é se você tiver vários threads ou vários processos apontando para uma única variável, um thread poderá ler e outro thread poderá gravar. Se eles atingirem ao mesmo tempo, é garantido que o encadeamento do leitor obtenha um dos dois valores: antes da alteração ou após a alteração. O que o atômico não oferece é qualquer tipo de garantia sobre quais desses valores você pode obter. Atomic é realmente comumente confundido com segurança de thread, e isso não está correto. Você precisa garantir a segurança da sua linha de outras maneiras.

não atômico

Por outro lado, não atômico, como você provavelmente pode adivinhar, significa apenas "não faça essas coisas atômicas". O que você perde é essa garantia de que você sempre recebe algo. Se você tentar ler no meio de uma gravação, poderá recuperar dados de lixo. Mas, por outro lado, você vai um pouco mais rápido. Como as propriedades atômicas precisam fazer alguma mágica para garantir que você recupere um valor, elas são um pouco mais lentas. Se for uma propriedade que você está acessando muito, pode usar a opção não-atômica para garantir que você não incorra nessa penalidade de velocidade. Acesso

cortesia https://academy.realm.io/posts/tmi-objective-c-property-attributes/

Os atributos da propriedade atomicidade (atômica e não atômica) não são refletidos na declaração de propriedade Swift correspondente, mas as garantias de atomicidade da implementação Objective-C ainda são mantidas quando a propriedade importada é acessada a partir do Swift.

Então - se você definir uma propriedade atômica no Objective-C, ela permanecerá atômica quando usada pelo Swift.

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

Suraj K Thomas
fonte
5

A propriedade atômica garante reter um valor totalmente inicializado, independentemente de quantos encadeamentos estão executando getter & setter nele.

A propriedade não atômica especifica que os acessadores sintetizados simplesmente configuram ou retornam um valor diretamente, sem garantias sobre o que acontece se esse mesmo valor for acessado simultaneamente a partir de diferentes threads.

Laxman Sahni
fonte
3

Atômico significa que apenas um encadeamento pode acessar a variável por vez (tipo estático). Atomic é seguro para threads, mas é lento.

Não atômico significa que vários encadeamentos podem acessar a variável ao mesmo tempo (tipo dinâmico). Não atômico é thread inseguro, mas é rápido.

Kemo
fonte
1

Se você estiver usando atômica, isso significa que o encadeamento será seguro e somente leitura. Se você estiver usando não-atômico, significa que os vários encadeamentos acessam a variável e não são seguros, mas são executados rapidamente, executam operações de leitura e gravação; esse é um tipo dinâmico.

Preetha
fonte
1

A verdade é que eles usam o bloqueio de rotação para implementar a propriedade atômica. O código como abaixo:

 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);
    }
Paulo
fonte
0

Para simplificar toda a confusão, vamos entender o bloqueio mutex.

O bloqueio Mutex, conforme o nome, bloqueia a mutabilidade do objeto. Portanto, se o objeto for acessado por uma classe, nenhuma outra classe poderá acessar o mesmo objeto.

No iOS, @sychronisetambém fornece o bloqueio mutex. Agora, ele serve no modo FIFO e garante que o fluxo não seja afetado por duas classes que compartilham a mesma instância. No entanto, se a tarefa estiver no encadeamento principal, evite acessar o objeto usando propriedades atômicas, pois pode conter sua interface do usuário e degradar o desempenho.

Suryanarayan Sahu
fonte
-1

Atômica: Garanta a segurança da linha bloqueando a linha usando o NSLOCK.

Não atômico: não garante a segurança da linha, pois não há mecanismo de travamento da linha.

satisfharyan
fonte
-1

Propriedades atômicas : - Quando uma variável atribuída com propriedade atômica, que significa que ela possui apenas um acesso ao thread, ela será segura e será boa na perspectiva de desempenho, terá um comportamento padrão.

Propriedades não atômicas : - Quando uma variável atribuída com propriedade atômica, significa que ela tem acesso a vários segmentos e não será segura para threads e será lenta na perspectiva de desempenho, terá um comportamento padrão e quando dois threads diferentes quiserem acessar variáveis ​​ao mesmo tempo isso dará resultados inesperados.

ashish.surana
fonte