Saya ingin implementasi List<T>
sebagai properti yang dapat digunakan dengan aman tanpa keraguan.
Sesuatu seperti ini:
private List<T> _list;
private List<T> MyT
{
get { // return a copy of _list; }
set { _list = value; }
}
Sepertinya saya masih perlu mengembalikan salinan (kloning) dari koleksi jadi jika di suatu tempat kita mengulang koleksi dan pada saat yang sama mengatur koleksi, maka tidak ada pengecualian yang dimunculkan.
Bagaimana cara menerapkan properti koleksi aman thread?
c#
collections
properties
thread-safety
Xaqron
sumber
sumber
IList<T>
(vsList<T>
)?List<T>
diimplementasikan? Jika ya, dapatkah Anda memberikan antarmuka yang Anda butuhkan alih-alih bertanya tentang semua yangList<T>
sudah dimiliki?Jawaban:
Jika Anda menargetkan .Net 4 ada beberapa opsi di System.Collections.Concurrent Namespace
Anda bisa menggunakan
ConcurrentBag<T>
dalam kasus ini sebagai penggantiList<T>
sumber
ConcurrentBag
adalah koleksi tidak berurutan, jadi tidak sepertiList<T>
itu tidak menjamin pemesanan. Anda juga tidak dapat mengakses item dengan indeks.Bahkan karena mendapat suara terbanyak, orang biasanya tidak dapat mengambil
System.Collections.Concurrent.ConcurrentBag<T>
pengganti yang aman untuk threadSystem.Collections.Generic.List<T>
apa adanya (Radek Stromský sudah menunjukkannya) tidak dipesan.Tetapi ada kelas yang disebut
System.Collections.Generic.SynchronizedCollection<T>
sudah sejak .NET 3.0 bagian dari kerangka kerja, tetapi itu tersembunyi dengan baik di lokasi di mana orang tidak berharap itu sedikit diketahui dan mungkin Anda tidak pernah tersandung di atasnya (setidaknya Saya tidak pernah).SynchronizedCollection<T>
dikompilasi menjadi System.ServiceModel.dll perakitan (yang merupakan bagian dari profil klien tetapi bukan dari perpustakaan kelas portabel).Semoga membantu.
sumber
Menurut saya, membuat sampel kelas ThreadSafeList akan mudah:
Anda cukup mengkloning daftar sebelum meminta pencacah, dan dengan demikian setiap pencacahan bekerja pada salinan yang tidak dapat diubah saat berjalan.
sumber
T
merupakan tipe referensi, bukankah ini hanya mengembalikan daftar baru yang berisi referensi ke semua objek asli? Jika demikian, pendekatan ini masih dapat menyebabkan masalah threading karena objek daftar dapat diakses oleh beberapa utas melalui "salinan" daftar yang berbeda.newList
tidak ada item yang ditambahkan atau dihapus yang akan membatalkan pencacah).Bahkan jawaban yang diterima adalah ConcurrentBag, saya rasa ini bukan pengganti daftar yang sebenarnya dalam semua kasus, karena komentar Radek terhadap jawaban tersebut mengatakan: "ConcurrentBag adalah koleksi tidak berurutan, jadi tidak seperti List, ia tidak menjamin pemesanan. Anda juga tidak dapat mengakses item berdasarkan indeks ".
Jadi, jika Anda menggunakan .NET 4.0 atau lebih tinggi, solusinya dapat menggunakan ConcurrentDictionary dengan integer TKey sebagai indeks array dan TValue sebagai nilai array. Ini adalah cara yang direkomendasikan untuk mengganti daftar di kursus Pluralsight C # Concurrent Collections . ConcurrentDictionary memecahkan kedua masalah yang disebutkan di atas: pengaksesan dan pemesanan indeks (kita tidak dapat mengandalkan pengurutan karena tabel hashnya ada di bawah tenda, tetapi implementasi .NET saat ini menyimpan urutan penambahan elemen).
sumber
ConcurrentDictionary
adalah kamus, bukan daftar. 2) Tidak ada jaminan untuk menjaga ketertiban, seperti jawaban Anda sendiri, yang bertentangan dengan alasan Anda untuk memposting jawaban. 3) Ini menautkan ke video tanpa membawa kutipan yang relevan ke dalam jawaban ini (yang mungkin tidak sesuai dengan lisensi mereka).current implementation
jika tidak secara eksplisit dijamin oleh dokumentasi. Implementasi dapat berubah sewaktu-waktu tanpa pemberitahuan.ArrayList
Kelas C # memilikiSynchronized
metode.Ini mengembalikan pembungkus aman utas di sekitar contoh apa pun
IList
. Semua operasi perlu dilakukan melalui pembungkusnya untuk memastikan keamanan benang.sumber
Jika Anda melihat kode sumber untuk Daftar T ( https://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs,c66df6f36c131877 ) Anda akan melihat ada kelas di sana (yang tentu saja internal - mengapa, Microsoft, mengapa?!?!) disebut SynchronizedList of T. Saya menyalin menempelkan kode di sini:
Secara pribadi saya pikir mereka tahu implementasi yang lebih baik menggunakan SemaphoreSlim dapat dibuat, tetapi tidak berhasil.
sumber
_root
) di setiap akses (baca / tulis) menjadikannya solusi yang lambat. Mungkin lebih baik kelas ini tetap internal.Clear()
setelah panggilan lainthis[index]
tetapi sebelum kunci diaktifkan.index
tidak lagi aman digunakan dan akan menampilkan pengecualian saat akhirnya dijalankan.Anda juga bisa menggunakan yang lebih primitif
kunci mana yang digunakan (lihat posting ini C # Mengunci sebuah objek yang dipindahkan ke blok kunci ).
Jika Anda mengharapkan pengecualian dalam kode ini tidak aman tetapi memungkinkan Anda untuk melakukan sesuatu seperti berikut:
Salah satu hal menyenangkan tentang ini adalah Anda akan mendapatkan kunci selama rangkaian operasi (daripada mengunci di setiap operasi). Yang berarti bahwa output harus keluar dalam bagian yang benar (penggunaan saya ini adalah mendapatkan beberapa output ke layar dari proses eksternal)
Saya sangat menyukai kesederhanaan + transparansi ThreadSafeList + yang melakukan bagian penting dalam menghentikan crash
sumber
Di .NET Core (versi apa pun), Anda dapat menggunakan ImmutableList , yang memiliki semua fungsionalitas
List<T>
.sumber
Saya yakin
_list.ToList()
akan membuatkan Anda salinan. Anda juga dapat menanyakannya jika Anda perlu seperti:Bagaimanapun, msdn mengatakan ini memang salinan dan bukan hanya referensi. Oh, dan ya, Anda harus mengunci metode set seperti yang ditunjukkan orang lain.
sumber
Sepertinya banyak orang yang menemukan ini menginginkan koleksi berukuran dinamis yang terindeks aman untuk utas. Hal terdekat dan termudah yang saya tahu adalah.
Ini akan mengharuskan Anda untuk memastikan kunci Anda terlibat dengan benar jika Anda menginginkan perilaku pengindeksan yang normal. Jika Anda berhati-hati, .count bisa cukup sebagai kunci untuk pasangan nilai kunci baru yang Anda tambahkan.
sumber
Saya akan menyarankan siapa pun yang berurusan dengan
List<T>
skenario multi-threading untuk melihat Koleksi Abadi, khususnya ImmutableArray .Saya merasa sangat berguna jika Anda memiliki:
Juga dapat berguna saat Anda perlu menerapkan semacam perilaku seperti transaksi (yaitu mengembalikan operasi penyisipan / pembaruan / penghapusan jika terjadi kegagalan)
sumber
Inilah kelas yang Anda minta:
sumber
this.GetEnumerator();
saat @Tejs menyarankanthis.Clone().GetEnumerator();
?[DataContract( IsReference = true )]
?Pada dasarnya jika Anda ingin menghitung dengan aman, Anda perlu menggunakan kunci.
Silakan merujuk ke MSDN tentang ini. http://msdn.microsoft.com/en-us/library/6sh2ey19.aspx
Berikut adalah bagian dari MSDN yang mungkin menarik bagi Anda:
Anggota publik statis (Dibagikan dalam Visual Basic) jenis ini adalah thread aman. Setiap anggota instance tidak dijamin aman untuk thread.
Sebuah Daftar dapat mendukung banyak pembaca secara bersamaan, selama koleksinya tidak diubah. Menghitung melalui koleksi pada dasarnya bukanlah prosedur yang aman untuk thread. Dalam kasus yang jarang terjadi di mana enumerasi bersaing dengan satu atau lebih akses tulis, satu-satunya cara untuk memastikan keamanan thread adalah dengan mengunci koleksi selama pencacahan keseluruhan. Agar koleksi dapat diakses oleh beberapa utas untuk membaca dan menulis, Anda harus menerapkan sinkronisasi Anda sendiri.
sumber
Berikut adalah kelas untuk daftar aman benang tanpa kunci
sumber
Gunakan
lock
pernyataan tersebut untuk melakukan ini. ( Baca di sini untuk informasi lebih lanjut. )FYI ini mungkin bukan apa yang Anda minta - Anda mungkin ingin mengunci lebih jauh dalam kode Anda tetapi saya tidak dapat berasumsi itu. Silakan lihat di
lock
kata kunci dan sesuaikan penggunaannya dengan situasi spesifik Anda.Jika perlu, Anda dapat
lock
di blokget
danset
menggunakan_list
variabel yang akan membuatnya jadi baca / tulis tidak dapat terjadi pada saat yang bersamaan.sumber
lock
pernyataan tersebut. Dengan menggunakan contoh serupa, saya dapat berpendapat bahwa kita tidak boleh menggunakan for loop karena Anda dapat membuat aplikasi deadlock dengan susah payah:for (int x = 0; x >=0; x += 0) { /* Infinite loop, oops! */ }
lock (this)
danlock (typeof(this))
sangat tidak boleh.