O que significa atomic
e o que nonatomic
significa nas declarações de propriedade?
@property(nonatomic, retain) UITextField *userName;
@property(atomic, retain) UITextField *userName;
@property(retain) UITextField *userName;
Qual é a diferença operacional entre esses três?
ios
objective-c
properties
atomic
nonatomic
Alex Wayne
fonte
fonte
Respostas:
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 de-nonatomic
atomic
foi 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:
Nesse caso, o segmento A pode renomear o objeto chamando
setFirstName:
e depois chamandosetLastName:
. Enquanto isso, o segmento B pode chamarfullName
entre 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
fullName
enquanto as propriedades dependentes estiverem sendo atualizadas.fonte
@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.atomic
impede leituras de meio valor de encadeamento cruzado. (Isso foi um erro divertido de rastrear.)retain/autorelease
dança. O segmento B libera o objeto. O segmento A vai crescer .atomic
garante que o segmento A tenha uma referência forte (uma contagem de retenção +1) para o valor de retorno.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.
Agora, a variante atômica é um pouco mais complicada:
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.
fonte
@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];
efoo.delegate = nil; self.foo = nil; [super dealloc];
. Consulte stackoverflow.com/questions/917884/…_val
/val
são, mas não, não realmente. O getter para uma propriedade atômicacopy
/retain
precisa 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).Atomic
Não atômico
fonte
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.
fonte
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.
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
nonatomic
o 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_msgSend
e examinaremos alguns resultados de alto nível do mundo real para muitas chamadas para umNSString
getter em casos não contestados (valores em segundos):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.
fonte
NSString
que 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@synchronized
comparaçã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
.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
nonatomic
porquenonatomic
nã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.
fonte
Encontrei uma explicação bastante bem posta das propriedades atômicas e não atômicas aqui . Aqui está um texto relevante do mesmo:
Como as
atomic
variá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-atomic
as variáveis, por outro lado, não oferecem essa garantia, mas oferecem o luxo de um acesso mais rápido. Para resumir, siga em frentenon-atomic
quando souber que suas variáveis não serão acessadas por vários threads simultaneamente e acelere as coisas.fonte
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:
atomic
// Padrãononatomic
strong = retain
// Padrãoweak = unsafe_unretained
retain
assign
// Padrãounsafe_unretained
copy
readonly
readwrite
// PadrãoNo artigo Atributos ou modificadores de propriedade variável no iOS, você pode encontrar todos os atributos mencionados acima e isso definitivamente o ajudará.
atomic
atomic
significa que apenas um encadeamento acessa a variável (tipo estático).atomic
é seguro para discussão.atomic
é o comportamento padrãoExemplo:
nonatomic
nonatomic
significa que vários threads acessam a variável (tipo dinâmico).nonatomic
é inseguro para thread.nonatomic
NÃO é um comportamento padrão. Precisamos adicionar anonatomic
palavra - chave no atributo de propriedade.Exemplo:
fonte
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.
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.
fonte
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.
fonte
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.
fonte
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:
é seguro para discussão.
NÃO é seguro para threads.
fonte
Não existe essa palavra-chave "atômica"
Podemos usar o acima, como
Consulte a pergunta sobre estouro de pilha . Estou tendo problemas se usar NSString * myString @property (atomic, reter) .
fonte
Veja mais aqui: https://realm.io/news/tmi-objective-c-property-attributes/
fonte
O padrão é que
atomic
isso 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:
Portanto, esses dois últimos são os mesmos:
Por outro lado, não
nonatomic
adiciona nada ao seu código. Portanto, é apenas thread-safe se você codificar o mecanismo de segurança.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!
fonte
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á SEMPREO 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
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.
fonte
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.
fonte
Como declarar:
Como atômico é o padrão,
E no arquivo de implementação
Suponha que uma tarefa relacionada a três propriedades seja
Todas as propriedades funcionam paralelamente (como assincronamente).
Se você chamar "nome" do segmento A ,
E
Ao mesmo tempo, se você ligar
da linha B ,
Agora, se a propriedade * name não for atômica ,
É 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
É 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
fonte
atomic
é 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).Atomicidade atômica (padrão)
não atômico
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
fonte
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.
fonte
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.
fonte
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.
fonte
A verdade é que eles usam o bloqueio de rotação para implementar a propriedade atômica. O código como abaixo:
fonte
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,
@sychronise
també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.fonte
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.
fonte
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.
fonte