Apa perbedaan antara atribut atomik dan nonatomik?

Jawaban:

1761

Dua yang terakhir identik; "atomic" adalah perilaku default ( perhatikan bahwa itu sebenarnya bukan kata kunci; itu hanya ditentukan oleh tidak adanyanonatomic - atomicditambahkan sebagai kata kunci dalam versi terbaru dari llvm / dentang).

Dengan asumsi bahwa Anda sedang mensintesis implementasi metode, atom vs non-atom mengubah kode yang dihasilkan. Jika Anda menulis setter / getter Anda sendiri, atom / nonatomik / retain / assign / copy hanyalah nasihat. (Catatan: @synthesize sekarang menjadi perilaku default di LLVM versi terbaru. Juga tidak perlu mendeklarasikan variabel instan; mereka juga akan disintesis secara otomatis, dan akan memiliki _prepended pada namanya untuk mencegah akses langsung yang tidak disengaja).

Dengan "atomik", pembuat / pengambil yang disintesis akan memastikan bahwa seluruh nilai selalu dikembalikan dari pengambil atau ditetapkan oleh pembuat, terlepas dari aktivitas pembuat pada thread lain. Yaitu, jika utas A berada di tengah pengambil sementara utas B memanggil setter, nilai aktual yang sebenarnya - objek autoreleased, kemungkinan besar - akan dikembalikan ke pemanggil di A.

Dalam nonatomic, tidak ada jaminan yang dibuat. Dengan demikian, nonatomicjauh lebih cepat daripada "atom".

Apa yang "atom" tidak lakukan adalah membuat jaminan tentang keamanan benang. Jika utas A memanggil pengambil secara bersamaan dengan utas B dan C memanggil setter dengan nilai yang berbeda, utas A dapat mendapatkan salah satu dari tiga nilai yang dikembalikan - yang sebelum pemukim dipanggil atau salah satu dari nilai yang dilewatkan ke setter dalam B dan C. Demikian juga, objek mungkin berakhir dengan nilai dari B atau C, tidak ada cara untuk mengatakan.

Memastikan integritas data - salah satu tantangan utama pemrograman multi-ulir - dicapai dengan cara lain.

Menambah ini:

atomicity dari satu properti juga tidak dapat menjamin keamanan utas saat beberapa properti dependen sedang bermain.

Mempertimbangkan:

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

Dalam hal ini, utas A dapat mengubah nama objek dengan memanggil setFirstName:dan kemudian memanggil setLastName:. Sementara itu, utas B dapat memanggil fullNamedi antara dua utas A dan akan menerima nama depan yang baru ditambah dengan nama belakang yang lama.

Untuk mengatasinya, Anda memerlukan model transaksional . Yaitu beberapa jenis sinkronisasi dan / atau pengecualian yang memungkinkan seseorang untuk mengecualikan akses ke fullNamesementara properti dependen sedang diperbarui.

Bbum
sumber
21
Mengingat bahwa setiap kode thread-aman akan melakukan penguncian sendiri dll, kapan Anda ingin menggunakan pengakses properti atom? Saya kesulitan memikirkan contoh yang baik.
Daniel Dickison
8
@bbum Masuk akal. Saya suka komentar Anda untuk jawaban lain bahwa keamanan thread lebih merupakan masalah tingkat model. Dari definisi keamanan utas IBM: ibm.co/yTEbjY "Jika sebuah kelas diimplementasikan dengan benar, yang merupakan cara lain untuk mengatakan bahwa itu sesuai dengan spesifikasinya, tidak ada urutan operasi (membaca atau menulis bidang publik dan panggilan ke metode publik) pada objek kelas itu harus dapat menempatkan objek ke dalam keadaan tidak valid, mengamati objek menjadi dalam keadaan tidak valid, atau melanggar salah satu dari invarian kelas, prasyarat, atau postkondisi. "
Ben Flynn
6
Berikut ini contoh yang mirip dengan @StevenKramer: Saya punya @property NSArray* astronomicalEvents;data daftar yang ingin saya tampilkan di UI. Ketika aplikasi meluncurkan pointer menunjuk ke array kosong, maka aplikasi menarik data dari web. Ketika permintaan web selesai (di utas berbeda) aplikasi membangun array baru kemudian secara atomis mengatur properti ke nilai pointer baru. Ini thread aman dan saya tidak perlu menulis kode penguncian, kecuali saya kehilangan sesuatu. Sepertinya cukup berguna bagi saya.
bugloaf
10
@HotLicks Satu lagi kesenangan; pada arsitektur tertentu (Tidak ingat yang mana), nilai 64 bit yang dilewati sebagai argumen mungkin dilewatkan setengah dalam register dan setengah pada stack. atomicmencegah cross-thread membaca setengah nilai. (Itu bug yang menyenangkan untuk dilacak.)
bbum
8
@congliu Thread A mengembalikan objek tanpa retain/autoreleasemenari. Thread B melepaskan objek. Thread A menjadi booming . atomicmemastikan bahwa utas A memiliki referensi yang kuat (jumlah penahan +1) untuk nilai pengembalian.
bbum
360

Ini dijelaskan dalam dokumentasi Apple , tetapi di bawah ini adalah beberapa contoh dari apa yang sebenarnya terjadi.

Perhatikan bahwa tidak ada kata kunci "atom", jika Anda tidak menentukan "nonatomik", maka propertinya adalah atom, tetapi menentukan "atom" secara eksplisit akan menghasilkan kesalahan.

Jika Anda tidak menentukan "nonatomik", maka propertinya adalah atomik, tetapi Anda masih bisa menentukan "atomik" secara eksplisit dalam versi terbaru jika Anda mau.

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

- (UITextField *) userName {
    return userName;
}

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

Sekarang, varian atom sedikit lebih rumit:

//@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_;
    }
}

Pada dasarnya, versi atom harus mengambil kunci untuk menjamin keamanan benang, dan juga menabrak jumlah referensi pada objek (dan jumlah autorelease untuk menyeimbangkannya) sehingga objek dijamin ada untuk pemanggil, jika tidak ada adalah kondisi lomba yang potensial jika utas lain menetapkan nilai, yang menyebabkan jumlah referensi turun menjadi 0.

Sebenarnya ada sejumlah besar varian yang berbeda tentang bagaimana hal-hal ini bekerja tergantung pada apakah properti adalah nilai skalar atau objek, dan bagaimana mempertahankan, menyalin, membaca, nonatomik, dll berinteraksi. Secara umum synthesizer properti hanya tahu bagaimana melakukan "hal yang benar" untuk semua kombinasi.

Louis Gerbarg
sumber
8
@Louis Gerbarg: Saya percaya versi setter (nonatomic, retain) Anda tidak akan berfungsi dengan baik jika Anda mencoba menetapkan objek yang sama (yaitu: userName == userName_)
Florin
5
Kode Anda sedikit menyesatkan; tidak ada jaminan tentang apa yang disinkronkan getter / setters. Secara kritis, @property (assign) id delegate;tidak disinkronkan pada apa pun (iOS SDK GCC 4.2 ARM -Os), yang berarti ada ras antara [self.delegate delegateMethod:self];dan foo.delegate = nil; self.foo = nil; [super dealloc];. Lihat stackoverflow.com/questions/917884/…
tc.
@fyolnish Saya tidak yakin apa yang _val/ valyang, tapi tidak, tidak benar-benar. Para pengambil untuk atom copy/ retainproperti perlu memastikan bahwa ia tidak mengembalikan objek yang refcount-nya menjadi nol karena setter dipanggil di utas lain, yang pada dasarnya berarti perlu membaca ivar, mempertahankannya sambil memastikan bahwa setter belum ditimpa-dan-dirilis itu, dan kemudian lepas otomatis untuk menyeimbangkan mempertahankan. Itu pada dasarnya berarti baik pengambil dan penyetel harus menggunakan kunci (jika tata letak memori diperbaiki itu harus bisa dilakukan dengan instruksi CAS2; sayangnya -retainadalah panggilan metode).
tc.
@ tc Sudah cukup lama tetapi apa yang saya maksud untuk menulis mungkin adalah ini: gist.github.com/fjolnir/5d96b3272c6255f6baae Tapi ya mungkin nilai lama dibaca oleh pembaca sebelum setFoo: kembali, dan dirilis sebelum pembaca mengembalikannya. Tapi mungkin jika setter menggunakan -autorelease bukan -release, itu akan memperbaikinya.
Fjölnir
@fyolnish Sayangnya, tidak: Itu autoreleases pada utter setter, sementara itu perlu autoreleases pada utter pengambil. Sepertinya ada peluang (ramping) untuk kehabisan tumpukan karena Anda menggunakan rekursi.
tc.
170

Atom

  • adalah perilaku default
  • akan memastikan proses ini diselesaikan oleh CPU, sebelum proses lain mengakses variabel
  • tidak cepat, karena memastikan prosesnya selesai sepenuhnya

Non-Atom

  • BUKAN perilaku default
  • lebih cepat (untuk kode yang disintesis, yaitu, untuk variabel yang dibuat menggunakan @property dan @synthesize)
  • tidak aman untuk benang
  • dapat mengakibatkan perilaku tak terduga, ketika dua proses berbeda mengakses variabel yang sama pada saat yang sama
raw3d
sumber
137

Cara terbaik untuk memahami perbedaannya adalah dengan menggunakan contoh berikut.

Misalkan ada properti string atom yang disebut "nama", dan jika Anda menelepon [self setName:@"A"]dari utas A, menelepon [self setName:@"B"]dari utas B, dan menelepon [self name]dari utas C, maka semua operasi pada utas berbeda akan dilakukan secara seri yang artinya jika satu utas menjalankan setter atau pengambil, maka utas lainnya akan menunggu.

Ini membuat properti "nama" aman untuk baca / tulis, tetapi jika utas lainnya, D, memanggil [name release]secara bersamaan maka operasi ini mungkin menghasilkan kerusakan karena tidak ada panggilan setter / pengambil yang terlibat di sini. Yang berarti suatu objek membaca / menulis aman (ATOMI), tetapi tidak aman-utas karena utas lainnya dapat secara bersamaan mengirim semua jenis pesan ke objek. Pengembang harus memastikan keamanan utas untuk objek tersebut.

Jika properti "nama" adalah nonatomik, maka semua utas dalam contoh di atas - A, B, C dan D akan dieksekusi secara bersamaan menghasilkan hasil yang tidak terduga. Dalam hal atom, salah satu dari A, B atau C akan dieksekusi terlebih dahulu, tetapi D masih dapat dieksekusi secara paralel.

Vijayendra
sumber
116

Sintaks dan semantik sudah didefinisikan dengan baik oleh jawaban-jawaban bagus lainnya untuk pertanyaan ini. Karena eksekusi dan kinerja tidak dirinci dengan baik, saya akan menambahkan jawaban saya.

Apa perbedaan fungsional antara 3 ini?

Saya selalu menganggap atom sebagai standar cukup aneh. Pada tingkat abstraksi tempat kami bekerja, menggunakan properti atom untuk kelas sebagai kendaraan untuk mencapai 100% keselamatan benang adalah kasus sudut. Untuk program multithread yang benar-benar benar, intervensi oleh programmer hampir pasti merupakan persyaratan. Sementara itu, karakteristik dan eksekusi kinerja belum dirinci secara mendalam. Setelah menulis beberapa program multithreaded selama bertahun-tahun, saya telah menyatakan properti saya nonatomicsepanjang waktu karena atom tidak masuk akal untuk tujuan apa pun. Selama diskusi tentang rincian sifat atomik dan nonatomik pertanyaan ini , saya melakukan beberapa profil yang menemukan beberapa hasil yang aneh.

Eksekusi

Baik. Hal pertama yang saya ingin jelaskan adalah bahwa implementasi penguncian adalah implementasi yang didefinisikan dan disarikan. Louis menggunakan @synchronized(self)dalam contohnya - Saya telah melihat ini sebagai sumber kebingungan yang umum. Implementasinya tidak benar - benar digunakan @synchronized(self); ia menggunakan kunci putaran tingkat objek . Ilustrasi Louis baik untuk ilustrasi tingkat tinggi menggunakan konstruksi yang kita semua kenal, tetapi penting untuk mengetahui bahwa itu tidak digunakan @synchronized(self).

Perbedaan lain adalah bahwa sifat atom akan mempertahankan / melepaskan siklus objek Anda dalam pengambil.

Performa

Inilah bagian yang menarik: Kinerja menggunakan akses properti atom dalam kasus-kasus yang tidak diperdebatkan (misalnya single-threaded) bisa sangat sangat cepat dalam beberapa kasus. Dalam kasus yang kurang ideal, penggunaan akses atom dapat menelan biaya lebih dari 20 kali biaya overhead nonatomic. Sementara case yang diperebutkan menggunakan 7 thread adalah 44 kali lebih lambat untuk struct tiga byte (2.2 GHz Core i7 Quad Core, x86_64). Struct tiga byte adalah contoh dari properti yang sangat lambat.

Catatan samping yang menarik: Aksesor yang ditentukan pengguna dari struct tiga byte adalah 52 kali lebih cepat dari accessor atom yang disintesis; atau 84% kecepatan aksesor nonatomik yang disintesis.

Objek dalam kasus yang diperebutkan juga dapat melebihi 50 kali.

Karena jumlah optimasi dan variasi dalam implementasi, sangat sulit untuk mengukur dampak dunia nyata dalam konteks ini. Anda mungkin sering mendengar sesuatu seperti "Percayai, kecuali jika Anda profil dan menemukan itu masalah". Karena tingkat abstraksi, sebenarnya cukup sulit untuk mengukur dampak aktual. Memungut biaya aktual dari profil bisa sangat memakan waktu, dan karena abstraksi, cukup tidak akurat. Selain itu, ARC vs MRC dapat membuat perbedaan besar.

Jadi mari kita mundur, tidak fokus pada implementasi akses properti, kami akan menyertakan tersangka seperti objc_msgSend, dan memeriksa beberapa hasil tingkat tinggi dunia nyata untuk banyak panggilan ke NSStringpengambil dalam kasus yang tidak terbantahkan (nilai dalam hitungan detik):

  • MRC | nonatomik | getter yang diterapkan secara manual: 2
  • MRC | nonatomik | pembuat getah disintesis: 7
  • MRC | atom | pembuat getah disintesis: 47
  • ARC | nonatomik | pengambil sintetis: 38 (catatan: ARC menambahkan hitungan hitungan bersepeda di sini)
  • ARC | atom | pembuat getah disintesis: 47

Seperti yang mungkin sudah Anda duga, aktivitas penghitungan referensi / bersepeda adalah kontributor signifikan dengan atom dan di bawah ARC. Anda juga akan melihat perbedaan yang lebih besar dalam kasus yang diperebutkan.

Meskipun saya memperhatikan kinerja, saya masih mengatakan Semantik Pertama! . Sementara itu, kinerja adalah prioritas rendah untuk banyak proyek. Namun, mengetahui detail eksekusi dan biaya teknologi yang Anda gunakan tentu tidak ada salahnya. Anda harus menggunakan teknologi yang tepat untuk kebutuhan, tujuan, dan kemampuan Anda. Mudah-mudahan ini akan menghemat beberapa jam perbandingan, dan membantu Anda membuat keputusan yang lebih baik saat merancang program Anda.

justin
sumber
MRC | atom | rajin sintesis: 47 ARC | atom | pengambil yang disintesis: 47 Apa yang membuat mereka sama? Bukankah seharusnya ARC memiliki lebih banyak overhead?
SDEZero
2
Jadi, jika sifat-sifat atomnya buruk, apakah sifatnya default. Untuk menambah kode boilerplate?
Kunal Balani
@ LearnCocos2D saya baru saja menguji pada 10.8.5 pada mesin yang sama, menargetkan 10.8, untuk case berulir tunggal yang tidak terbantahkan dengan NSStringyang tidak abadi: -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%- hasilnya sedikit berbeda hari ini. Saya tidak melakukan @synchronizedperbandingan. @synchronizedsecara semantik berbeda, dan saya tidak menganggapnya sebagai alat yang baik jika Anda memiliki program bersamaan nontrivial. jika Anda membutuhkan kecepatan, hindari @synchronized.
justin
apakah Anda memiliki tes ini di suatu tempat secara online? Saya terus menambahkan milik saya di sini: github.com/LearnCocos2D/LearnCocos2D/tree/master/…
LearnCocos2D
@ LearnCocos2D saya belum menyiapkannya untuk konsumsi manusia, maaf.
justin
95

Atom = keamanan utas

Non-atomik = Tidak ada keamanan benang

Keamanan benang:

Variabel Instance aman untuk digunakan jika mereka berperilaku dengan benar ketika diakses dari banyak utas, terlepas dari penjadwalan atau interleaving dari pelaksanaan utas tersebut dengan lingkungan runtime, dan tanpa sinkronisasi tambahan atau koordinasi lainnya pada bagian dari kode panggilan.

Dalam konteks kami:

Jika utas mengubah nilai instance, nilai yang diubah tersedia untuk semua utas, dan hanya satu utas yang dapat mengubah nilai sekaligus.

Tempat menggunakan atomic:

jika variabel instance akan diakses di lingkungan multithreaded.

Implikasi dari atomic:

Tidak secepat nonatomickarena nonatomictidak memerlukan pengawas bekerja dari itu dari runtime.

Tempat menggunakan nonatomic:

Jika variabel instan tidak akan diubah oleh banyak utas, Anda dapat menggunakannya. Ini meningkatkan kinerja.

Durai Amuthan.H
sumber
3
Semua yang Anda katakan di sini benar, tetapi kalimat terakhir pada dasarnya "salah", Dura, untuk pemrograman hari ini. Ini benar-benar tak terbayangkan Anda akan repot untuk mencoba "meningkatkan kinerja" dengan cara ini. (Maksud saya, sebelum Anda berada dalam tahun cahaya itu, Anda akan "tidak menggunakan ARC", "tidak menggunakan NSString karena lambat!" Dan seterusnya.) Untuk membuat contoh ekstrem, itu seperti mengatakan "tim, jangan beri komentar apa pun dalam kode, karena itu memperlambat kami. " Tidak ada jalur pengembangan yang realistis di mana Anda menginginkan keuntungan kinerja teoretis (tidak ada) demi tidak dapat diandalkan.
Fattie
3
@JoeBlow ini faktanya, Anda dapat memverifikasinya di sini developer.apple.com/library/mac/documentation/Cocoa/Conceptual/…
Durai Amuthan.H
1
Durai, FWIW, tautan itu secara langsung bertentangan dengan tesis Anda tentang “Atomic = thread safety”. Dalam dokumen tersebut, Apple secara eksplisit mengatakan, "Atomisitas properti tidak identik dengan keamanan utas objek." Dalam praktiknya, atom jarang cukup untuk mencapai keamanan ulir.
Rob
69

Saya menemukan penjelasan yang cukup baik tentang sifat atom dan non-atom di sini . Berikut beberapa teks yang relevan dari yang sama:

'atom' berarti itu tidak dapat dipecah. Dalam istilah OS / pemrograman, pemanggilan fungsi atom adalah panggilan yang tidak dapat diinterupsi - seluruh fungsi harus dijalankan, dan tidak diganti dari CPU oleh konteks operasi OS yang biasa sampai selesai. Kalau-kalau Anda tidak tahu: karena CPU hanya dapat melakukan satu hal pada suatu waktu, OS memutar akses ke CPU untuk semua proses yang berjalan dalam sedikit waktu-irisan, untuk memberikan ilusimultitasking. Penjadwal CPU dapat (dan tidak) mengganggu proses pada titik mana pun dalam pelaksanaannya - bahkan di panggilan fungsi menengah. Jadi untuk tindakan seperti memperbarui variabel penghitung bersama di mana dua proses dapat mencoba memperbarui variabel pada saat yang sama, mereka harus dieksekusi 'secara atomis', yaitu, setiap tindakan pembaruan harus selesai secara keseluruhan sebelum proses lain dapat ditukar ke CPU.

Jadi saya akan menebak bahwa atom dalam hal ini berarti metode pembaca atribut tidak dapat terganggu - yang berarti variabel yang sedang dibaca oleh metode tidak dapat mengubah nilainya setengah jalan karena beberapa utas / panggilan / fungsi lain mendapat menukar ke CPU.

Karena atomicvariabel tidak dapat diganggu, nilai yang terkandung oleh mereka di titik mana pun (kunci-kunci) dijamin tidak akan terganggu , meskipun, memastikan kunci ulir ini membuat akses ke mereka lebih lambat. non-atomicvariabel, di sisi lain, tidak membuat jaminan seperti itu tetapi menawarkan kemewahan akses yang lebih cepat. Singkatnya, ikuti non-atomicketika Anda tahu variabel Anda tidak akan diakses oleh beberapa utas secara bersamaan dan mempercepatnya.

tipycalFlow
sumber
1
Tautan rusak. ; (
Rob
Itulah masalah dengan tautan :( untungnya, saya telah mengutip teks yang relevan dalam jawaban saya
tipycalFlow
67

Setelah membaca begitu banyak artikel, posting Stack Overflow dan membuat aplikasi demo untuk memeriksa atribut atribut variabel, saya memutuskan untuk menggabungkan semua informasi atribut:

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

Dalam artikel atribut properti pengubah atau variabel di iOS Anda dapat menemukan semua atribut yang disebutkan di atas, dan itu pasti akan membantu Anda.

  1. atomic

    • atomic berarti hanya satu utas yang mengakses variabel (tipe statis).
    • atomic aman untuk thread.
    • Namun kinerjanya lambat
    • atomic adalah perilaku default
    • Accessor atom di lingkungan yang dikumpulkan tanpa sampah (yaitu saat menggunakan retain / release / autorelease) akan menggunakan kunci untuk memastikan bahwa utas lain tidak mengganggu pengaturan / perolehan nilai yang benar.
    • Ini sebenarnya bukan kata kunci.

    Contoh:

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

    • nonatomic berarti beberapa utas mengakses variabel (tipe dinamis).
    • nonatomic tidak aman
    • Tetapi cepat dalam kinerja
    • nonatomicBUKAN perilaku default. Kami perlu menambahkan nonatomickata kunci dalam atribut properti.
    • Ini dapat mengakibatkan perilaku tak terduga, ketika dua proses (utas) yang berbeda mengakses variabel yang sama pada saat yang sama.

    Contoh:

        @property (nonatomic, retain) NSString *name;
    
        @synthesize name;
swiftBoy
sumber
Bagaimana menetapkan dan memperkuat / mempertahankan keduanya sebagai default?
BangOperator
kuat datang dengan ARC, mempertahankan standar sebelum ARC
abdullahselek
56

Atom:

Atomic menjamin bahwa akses ke properti akan dilakukan dengan cara atom. Misalnya selalu mengembalikan objek yang diinisialisasi penuh, setiap get / set properti pada satu utas harus diselesaikan sebelum yang lain dapat mengaksesnya.

Jika Anda membayangkan fungsi berikut terjadi pada dua utas sekaligus Anda dapat melihat mengapa hasilnya tidak akan cantik.

-(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;
  }

  ...
}

Kelebihan: Pengembalian objek yang diinisialisasi penuh setiap kali menjadikannya pilihan terbaik jika multi-threading.

Cons: Performance hit, membuat eksekusi sedikit lebih lambat

Non-Atom:

Tidak seperti Atomic, itu tidak memastikan objek yang diinisialisasi penuh kembali setiap kali.

Pro: Eksekusi yang sangat cepat.

Cons: Peluang nilai sampah dalam kasus multi-threading.

Andrew Grant
sumber
5
Komentar itu tidak masuk akal. Bisakah Anda mengklarifikasi? Jika Anda melihat contoh di situs Apple maka kata kunci atom akan disinkronkan pada objek sambil memperbarui propertinya.
Andrew Grant
52

Jawaban termudah pertama: Tidak ada perbedaan antara dua contoh kedua Anda. Secara default, pengakses properti adalah atom.

Accessor atom di lingkungan yang dikumpulkan tanpa sampah (yaitu saat menggunakan retain / release / autorelease) akan menggunakan kunci untuk memastikan bahwa utas lain tidak mengganggu pengaturan / perolehan nilai yang benar.

Lihat bagian " Performance and Threading " dari dokumentasi Objective-C 2.0 Apple untuk beberapa informasi lebih lanjut dan untuk pertimbangan lain saat membuat aplikasi multi-utas.

Jay O'Conor
sumber
8
Dua alasan. Pertama, untuk kode yang disintesis itu menghasilkan lebih cepat (tetapi bukan kode threadsafe). Kedua, jika Anda menulis pengakses pelanggan yang bukan atomik, Anda dapat membuat anotasi bagi pengguna di masa depan bahwa kode tersebut tidak berupa atom ketika mereka membaca antarmuka, tanpa membuatnya menjadi implementasi.
Louis Gerbarg
31

Atomic berarti hanya satu utas yang mengakses variabel (tipe statis). Atomic aman dari benang, tetapi lambat.

Nonatomik berarti beberapa utas mengakses variabel (tipe dinamis). Nonatomic tidak aman, tetapi cepat.

IOS Rocks
sumber
14

Atomic aman untuk thread , lambat dan meyakinkan (tidak dijamin) bahwa hanya nilai yang dikunci disediakan tidak peduli berapa banyak utas yang mencoba mengakses zona yang sama. Saat menggunakan atom, sepotong kode yang ditulis di dalam fungsi ini menjadi bagian dari bagian kritis, yang hanya dapat dijalankan oleh satu utas.

Itu hanya menjamin keamanan benang; itu tidak menjamin itu. Maksud saya adalah Anda menyewa pengemudi ahli untuk mobil Anda, tetap saja itu tidak menjamin mobil tidak akan menemui kecelakaan. Namun, probabilitas tetap sedikit.

Atom - tidak dapat diuraikan, jadi hasilnya diharapkan. Dengan nonatomik - ketika utas lain mengakses zona memori, ia dapat memodifikasinya, sehingga hasilnya tidak terduga.

Pembicaraan kode:

Pembuat getar dan penyetel thread properti aman. misalnya jika Anda telah menulis:

self.myProperty = value;

aman untuk thread.

[myArray addObject:@"Abc"] 

TIDAK aman untuk thread.


sumber
Saya tidak tahu bagaimana paragraf terakhir muncul, tetapi itu sederhana salah, tidak ada yang namanya "salinan pribadi".
puncaknya
13

Tidak ada kata kunci "atomik" seperti itu

@property(atomic, retain) UITextField *userName;

Kita bisa menggunakan seperti di atas

@property(retain) UITextField *userName;

Lihat pertanyaan Stack Overflow Saya mendapatkan masalah jika saya menggunakan @property (atomic, retain) NSString * myString .

Deepak
sumber
10
"Ada kata kunci seperti itu", Bahwa kata kunci tidak diperlukan secara default dan bahkan adalah nilai default tidak berarti kata kunci tersebut tidak ada.
Matthijn
4
Ini salah. Kata kunci memang ada. Jawaban ini menyesatkan, dan saya mendorong untuk menghapusnya.
sethfri
12

atom (standar)

Atom adalah default: jika Anda tidak mengetik apa pun, properti Anda adalah atom. Properti atom dijamin bahwa jika Anda mencoba membaca darinya, Anda akan mendapatkan kembali nilai yang valid. Itu tidak membuat jaminan tentang apa nilai itu mungkin, tetapi Anda akan mendapatkan kembali data yang baik, bukan hanya memori sampah. Apa yang memungkinkan Anda lakukan adalah jika Anda memiliki banyak utas atau beberapa proses yang menunjuk pada satu variabel, satu utas dapat membaca dan utas lainnya dapat menulis. Jika mereka menekan pada saat yang sama, utas pembaca dijamin untuk mendapatkan salah satu dari dua nilai: baik sebelum perubahan atau setelah perubahan. Apa yang tidak diberikan atom kepada Anda adalah segala jenis jaminan tentang nilai-nilai mana yang mungkin Anda dapatkan. Atomik benar-benar sering dikacaukan dengan thread-safe, dan itu tidak benar. Anda perlu menjamin keselamatan utas Anda dengan cara lain.

nonatomik

Di sisi lain, non-atom, seperti yang bisa Anda tebak, hanya berarti, "jangan lakukan hal-hal atomik." Yang hilang adalah jaminan bahwa Anda selalu mendapatkan kembali sesuatu. Jika Anda mencoba membaca di tengah tulisan, Anda bisa mendapatkan kembali data sampah. Tetapi, di sisi lain, Anda bergerak sedikit lebih cepat. Karena sifat atom harus melakukan beberapa sihir untuk menjamin bahwa Anda akan mendapatkan kembali nilai, mereka sedikit lebih lambat. Jika itu adalah properti yang Anda akses banyak, Anda mungkin ingin turun ke nonatomik untuk memastikan bahwa Anda tidak dikenakan penalti kecepatan itu.

Lihat lebih lanjut di sini: https://realm.io/news/tmi-objective-c-property-attributes/

Proton
sumber
11

The standar adalah atomic, cara ini tidak dikenakan biaya kinerja setiap kali Anda menggunakan properti, tapi itu adalah thread aman. Apa yang dilakukan Objective-C adalah menyetel kunci, jadi hanya utas aktual yang dapat mengakses variabel, selama setter / pengambil dijalankan.

Contoh dengan MRC properti dengan ivar _internal:

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

Jadi dua yang terakhir ini sama:

@property(atomic, retain) UITextField *userName;

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

Di sisi lain tidak nonatomicmenambahkan apa pun ke kode Anda. Jadi aman saja jika Anda mengkode mekanisme keamanan sendiri.

@property(nonatomic, retain) UITextField *userName;

Kata kunci tidak harus ditulis sebagai atribut properti pertama sama sekali.

Jangan lupa, ini tidak berarti bahwa properti secara keseluruhan aman untuk digunakan. Hanya pemanggilan metode setter / pengambil adalah. Tetapi jika Anda menggunakan setter dan setelah itu rajin dengan 2 utas yang berbeda, itu bisa rusak juga!

Binarian
sumber
10

Sebelum Anda mulai: Anda harus tahu bahwa setiap objek dalam ingatan perlu dihapuskan dari ingatan agar terjadi penulis baru. Anda tidak bisa begitu saja menulis di atas sesuatu seperti yang Anda lakukan di atas kertas. Anda harus terlebih dahulu menghapus (membatalkan semua) dan kemudian Anda dapat menulis ke dalamnya. Jika pada saat itu penghapusan dilakukan (atau setengah selesai) dan belum ada yang ditulis (atau setengah ditulis) dan Anda mencoba untuk membacanya bisa sangat bermasalah! Atom dan nonatomik membantu Anda menangani masalah ini dengan cara yang berbeda.

Pertama baca pertanyaan ini dan kemudian baca jawaban Bbum . Selain itu, baca ringkasan saya.


atomic akan SELALU menjamin

  • Jika dua orang berbeda ingin membaca dan menulis pada saat yang sama, makalah Anda tidak akan terbakar! -> Aplikasi Anda tidak akan pernah crash, bahkan dalam kondisi balapan.
  • Jika satu orang mencoba untuk menulis dan hanya menulis 4 dari 8 huruf untuk ditulis, maka tidak dapat membaca di tengah, pembacaan hanya dapat dilakukan ketika semua 8 huruf ditulis -> Tidak membaca (dapatkan) akan terjadi pada 'utas yang masih menulis', yaitu jika ada 8 byte ke byte yang akan ditulis, dan hanya 4 byte yang ditulis —— hingga saat itu, Anda tidak diizinkan untuk membacanya. Tapi karena saya katakan itu tidak akan crash maka itu akan membaca dari nilai autoreleased objek .
  • Jika sebelum menulis Anda telah menghapus apa yang sebelumnya ditulis di atas kertas dan kemudian seseorang ingin membaca Anda masih bisa membaca. Bagaimana? Anda akan membaca dari sesuatu yang mirip dengan Mac OS Trash bin (karena Trash bin masih belum 100% terhapus ... itu dalam limbo) ---> Jika ThreadA ingin membaca sementara ThreadB telah dialokasikan untuk menulis, Anda akan mendapatkan sebuah nilai dari nilai akhir sepenuhnya yang ditulis oleh ThreadB atau dapatkan sesuatu dari kumpulan autorelease.

Mempertahankan jumlah adalah cara di mana memori dikelola di Objective-C. Saat Anda membuat objek, itu memiliki jumlah retain dari 1. Ketika Anda mengirim objek pesan retain, jumlah retainnya bertambah dengan 1. Ketika Anda mengirim objek pesan rilis, jumlah retainnya dikurangi oleh 1. Ketika Anda mengirim objek pesan autorelease , jumlah tetapnya dikurangi 1 pada beberapa tahap di masa depan. Jika jumlah penahan objek dikurangi menjadi 0, itu tidak dialokasikan.

  • Atomic tidak menjamin keamanan benang, meskipun berguna untuk mencapai keamanan benang. Keamanan Utas relatif terhadap cara Anda menulis kode / antrian utas tempat Anda membaca / menulis. Ini hanya menjamin multithreading yang tidak crash.

Apa?! Apakah multithreading dan keamanan thread berbeda?

Iya. Multithreading artinya: banyak utas dapat membaca bagian data yang dibagikan pada saat yang sama dan kami tidak akan crash, namun itu tidak menjamin bahwa Anda tidak membaca dari nilai yang bukan autoreleased. Dengan keamanan utas, dijamin apa yang Anda baca tidak dirilis secara otomatis. Alasan mengapa kita tidak membuat semuanya atom secara default adalah, bahwa ada biaya kinerja dan untuk sebagian besar hal tidak benar-benar membutuhkan keamanan thread. Beberapa bagian dari kode kita memerlukannya dan untuk beberapa bagian itu, kita perlu menulis kode kita dengan cara yang aman menggunakan kunci, mutex atau sinkronisasi.


nonatomic

  • Karena tidak ada yang namanya Mac OS Trash Bin, maka tidak ada yang peduli apakah Anda selalu mendapatkan nilai (<- Ini berpotensi menyebabkan crash), atau siapa pun yang peduli jika seseorang mencoba membaca setengah dari tulisan Anda (walaupun setengah menulis dalam memori sangat berbeda dari setengah menulis di atas kertas, pada memori itu bisa memberi Anda nilai bodoh yang gila dari sebelumnya, sementara di atas kertas Anda hanya melihat setengah dari apa yang telah ditulis) -> Tidak menjamin untuk tidak crash, karena tidak menggunakan mekanisme autorelease.
  • Tidak menjamin nilai tertulis penuh untuk dibaca!
  • Lebih cepat dari atom

Secara keseluruhan mereka berbeda dalam 2 aspek:

  • Menabrak atau tidak karena memiliki atau tidak memiliki kumpulan autorelease.

  • Mengizinkan dibaca tepat di tengah-tengah 'nilai yang belum selesai tulis atau kosong' atau tidak mengizinkan dan hanya memungkinkan untuk membaca ketika nilainya sepenuhnya ditulis.

Madu
sumber
9

Jika Anda menggunakan properti Anda dalam kode multi-threaded maka Anda akan dapat melihat perbedaan antara atribut nonatomik dan atomik. Nonatomik lebih cepat dari atom dan atom adalah benang-aman, bukan nonatomik.

Vijayendra Tripathi telah memberikan contoh untuk lingkungan multi-utas.

Ankul Gaur
sumber
9
  • -Atomic berarti hanya satu utas mengakses variabel (tipe statis).
  • -Atomik adalah thread yang aman.
  • -tapi lambat dalam kinerja

Cara mendeklarasikan:

Karena atom adalah standar,

@property (retain) NSString *name;

DAN dalam file implementasi

self.name = @"sourov";

Misalkan tugas yang terkait dengan tiga properti adalah

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

Semua properti bekerja secara paralel (seperti tidak sinkron).

Jika Anda memanggil "nama" dari utas A ,

Dan

Pada saat yang sama jika Anda menelepon

[self setName:@"Datta"]

dari utas B ,

Sekarang, jika * name property nonatomic, maka

  • Ini akan mengembalikan nilai "Datta" untuk A
  • Ini akan mengembalikan nilai "Datta" untuk B

Itu sebabnya non atom disebut thread tidak aman Tetapi tetapi kinerja cepat karena eksekusi paralel

Sekarang Jika * name property is atomic

  • Ini akan memastikan nilai "Sourov" untuk A
  • Maka akan mengembalikan nilai "Datta" untuk B

Karena itulah atom disebut thread Safe dan itulah sebabnya disebut read-write safe

Operasi situasi seperti itu akan dilakukan secara serial. Dan kinerja lambat

- Nonatomik berarti beberapa utas mengakses variabel (tipe dinamis).

- Nonatomic adalah utas yang tidak aman.

- tetapi cepat dalam kinerja

-Nonatomic BUKAN perilaku default, kita perlu menambahkan kata kunci nonatomic dalam atribut properti.

For In Swift Mengonfirmasi bahwa properti Swift adalah nonatomik dalam arti ObjC. Salah satu alasannya adalah agar Anda berpikir tentang apakah atomisitas per-properti cukup untuk kebutuhan Anda.

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

Untuk info lebih lanjut silakan kunjungi situs web http://rdcworld-iphone.blogspot.in/2012/12/variable-property-attributes-or.html

Shourob Datta
sumber
4
Seperti banyak banyak banyak maaaaany orang lain telah mengatakan, atomicadalah TIDAK benang-aman! Ini lebih tahan terhadap masalah thread, tetapi tidak aman untuk thread. Itu hanya memastikan Anda akan mendapatkan nilai keseluruhan, alias nilai "benar" (tingkat biner), tetapi tidak berarti itu akan memastikan bahwa itu adalah nilai saat ini dan "benar" untuk logika bisnis Anda (itu bisa menjadi nilai masa lalu dan tidak valid oleh logika Anda).
Alejandro Iván
6

Atomicity atomic (standar)

Atom adalah default: jika Anda tidak mengetik apa pun, properti Anda adalah atom. Properti atom dijamin bahwa jika Anda mencoba membaca darinya, Anda akan mendapatkan kembali nilai yang valid. Itu tidak membuat jaminan tentang apa nilai itu mungkin, tetapi Anda akan mendapatkan kembali data yang baik, bukan hanya memori sampah. Apa yang memungkinkan Anda lakukan adalah jika Anda memiliki banyak utas atau beberapa proses yang menunjuk pada satu variabel, satu utas dapat membaca dan utas lainnya dapat menulis. Jika mereka menekan pada saat yang sama, utas pembaca dijamin untuk mendapatkan salah satu dari dua nilai: baik sebelum perubahan atau setelah perubahan. Apa yang tidak diberikan atom kepada Anda adalah segala jenis jaminan tentang nilai-nilai mana yang mungkin Anda dapatkan. Atomik benar-benar sering dikacaukan dengan thread-safe, dan itu tidak benar. Anda perlu menjamin keselamatan utas Anda dengan cara lain.

nonatomik

Di sisi lain, non-atom, seperti yang bisa Anda tebak, hanya berarti, "jangan lakukan hal-hal atomik." Yang hilang adalah jaminan bahwa Anda selalu mendapatkan kembali sesuatu. Jika Anda mencoba membaca di tengah tulisan, Anda bisa mendapatkan kembali data sampah. Tetapi, di sisi lain, Anda bergerak sedikit lebih cepat. Karena sifat atom harus melakukan beberapa sihir untuk menjamin bahwa Anda akan mendapatkan kembali nilai, mereka sedikit lebih lambat. Jika itu adalah properti yang Anda akses banyak, Anda mungkin ingin turun ke nonatomik untuk memastikan bahwa Anda tidak dikenakan penalti kecepatan itu. Mengakses

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

Atribut properti Atomicity (atomik dan nonatomik) tidak tercermin dalam deklarasi properti Swift yang sesuai, tetapi jaminan atomisitas penerapan Objective-C masih berlaku ketika properti yang diimpor diakses dari Swift.

Jadi - jika Anda mendefinisikan properti atom di Objective-C itu akan tetap atom ketika digunakan oleh Swift.

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

Suraj K Thomas
sumber
5

Properti atom memastikan untuk mempertahankan nilai yang diinisialisasi penuh terlepas dari berapa banyak thread melakukan pengambil dan penyetel di atasnya.

Properti nonatomik menentukan bahwa aksesor disintesis hanya mengatur atau mengembalikan nilai secara langsung, tanpa jaminan tentang apa yang terjadi jika nilai yang sama diakses secara bersamaan dari utas yang berbeda.

Laxman Sahni
sumber
3

Atomic berarti hanya satu utas yang dapat mengakses variabel pada suatu waktu (tipe statis). Atomic aman dari benang, tetapi lambat.

Nonatomik berarti beberapa utas dapat mengakses variabel secara bersamaan (tipe dinamis). Nonatomic tidak aman, tetapi cepat.

Kemo
sumber
1

Jika Anda menggunakan atom, itu berarti utas akan aman dan hanya-baca. Jika Anda menggunakan nonatomik, itu berarti beberapa utas mengakses variabel dan utas tidak aman, tetapi dijalankan cepat, melakukan operasi baca dan tulis; ini adalah tipe dinamis.

Preetha
sumber
1

Yang benar adalah bahwa mereka menggunakan kunci putar untuk mengimplementasikan properti atom. Kode seperti di bawah ini:

 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);
    }
paul
sumber
0

Untuk menyederhanakan seluruh kebingungan, mari kita memahami kunci mutex.

Kunci mutex, sesuai namanya, mengunci mutabilitas objek. Jadi jika objek diakses oleh suatu kelas, tidak ada kelas lain yang dapat mengakses objek yang sama.

Di iOS, @sychronisejuga menyediakan kunci mutex. Sekarang berfungsi dalam mode FIFO dan memastikan alirannya tidak terpengaruh oleh dua kelas yang berbagi instance yang sama. Namun, jika tugas berada di utas utama, hindari mengakses objek menggunakan properti atom karena dapat menahan UI Anda dan menurunkan kinerja.

Suryanarayan Sahu
sumber
-1

Atom: Pastikan keamanan utas dengan mengunci utas menggunakan NSLOCK.

Non atom: Tidak memastikan keamanan ulir karena tidak ada mekanisme penguncian ulir.

satisharyan
sumber
-1

Properti atom : - Ketika sebuah variabel ditugaskan dengan properti atom yang berarti ia hanya memiliki satu akses utas dan itu akan menjadi thread aman dan akan baik dalam perspektif kinerja, akan memiliki perilaku default.

Properti Non Atom : - Ketika sebuah variabel ditugaskan dengan properti atom yang berarti ia memiliki akses multi-thread dan itu tidak akan thread aman dan akan lambat dalam perspektif kinerja, akan memiliki perilaku default dan ketika dua utas berbeda ingin mengakses variabel pada saat yang sama itu akan memberikan hasil yang tidak terduga.

ashish.surana
sumber