Dalam makalah dengan judul yang sama dengan pertanyaan ini, penulis menggambarkan bagaimana membangun operasi CAS multi-kata linearizable nonblocking hanya menggunakan CAS kata tunggal. Mereka pertama kali memperkenalkan operasi penukaran ganda-bandingkan-tunggal - RDCSS, sebagai berikut:
word_t RDCSS(RDCSSDescriptor_t *d) {
do {
r = CAS1(d->a2, d->o2, d);
if (IsDescriptor(r)) Complete(r);
} while (IsDescriptor(r));
if (r == d->o2) Complete(d); // !!
return r;
}
void Complete(RDCSSDescriptor_t *d) {
v = *(d->a1);
if (v == d->o1) CAS1(d->a2, d, d->n2);
else CAS1(d->a2, d, d->o2);
}
di mana RDCSSDescriptor_t
adalah struktur dengan bidang-bidang berikut:
a1
- alamat kondisi pertamao1
- nilai yang diharapkan di alamat pertamaa2
- alamat kondisi keduao2
- nilai yang diharapkan di alamat keduan2
- nilai baru yang akan ditulis di alamat kedua
Deskriptor ini dibuat dan diinisialisasi sekali dalam utas yang memulai operasi RDCSS - tidak ada utas lain yang memiliki referensi sampai CAS1 pertama dalam fungsi RDCSS
berhasil, membuat deskriptor dapat dijangkau (atau aktif dalam terminologi makalah ini).
Gagasan di balik algoritma adalah sebagai berikut - ganti lokasi memori kedua dengan deskriptor yang mengatakan apa yang ingin Anda lakukan. Kemudian, mengingat bahwa deskriptor hadir, periksa lokasi memori pertama untuk melihat apakah nilainya berubah. Jika belum, ganti deskriptor di lokasi memori kedua dengan nilai baru. Jika tidak, atur lokasi memori kedua kembali ke nilai lama.
Para penulis tidak menjelaskan mengapa garis dengan !!
komentar itu perlu dalam makalah. Tampak bagi saya bahwa CAS1
instruksi dalam Complete
fungsi akan selalu gagal setelah pemeriksaan ini, asalkan tidak ada modifikasi bersamaan. Dan jika ada modifikasi bersamaan antara cek dan CAS di Complete
, maka utas yang melakukan pemeriksaan harus tetap gagal dengan CAS-nya Complete
, karena modifikasi bersamaan tidak boleh menggunakan deskriptor yang sama d
.
Pertanyaan saya adalah: Dapatkah pemeriksaan dalam fungsi RDCSSS
, if (r == d->o2)...
dihilangkan, dengan RDCSS masih mempertahankan semantik dari instruksi pembandingan ganda, pertukaran tunggal yang linierisasi dan bebas kunci ? (baris dengan !!
komentar)
Jika tidak, dapatkah Anda menggambarkan skenario di mana garis ini sebenarnya diperlukan untuk memastikan kebenaran?
Terima kasih.
sumber
Jawaban:
Dalam lingkungan runtime bersamaan hal-hal sederhana bisa terasa aneh ... harap ini bisa membantu.
Kami memiliki BUILT-IN ATOMIC CAS1 yang memiliki semantik ini:
Kita perlu mendefinisikan fungsi RDCSS ATOMIC menggunakan CAS1 dan memiliki semantik berikut:
Secara intuitif: kita perlu mengubah nilai pada addr2 secara kontinyu hanya jika * addr1 == oldval1 ... jika utas lain mengubahnya, kita dapat membantu utas lainnya menyelesaikan operasi, maka kita bisa mencoba lagi.
Fungsi RDCSS akan digunakan (lihat artikel) untuk mendefinisikan CASN. Sekarang, kita mendefinisikan deskriptor RDCSS dengan cara berikut:
Kemudian kami mengimplementasikan RDCSS dengan cara berikut:
JAWABAN UNTUK PERTANYAAN ANDA
Jika kita menghilangkan STEP4 maka if (... && * addr1 == oldval1) * addr2 = newval2 bagian dari semantic RDCSS tidak akan pernah dieksekusi (... atau lebih baik: itu dapat dieksekusi dengan cara yang tidak dapat diramalkan oleh utas lain yang membantu yang sekarang).
Seperti yang Anda tunjukkan dalam komentar Anda, kondisi jika (res == d1-> oldval2) di STEP4 tidak diperlukan: bahkan jika kami menghilangkannya, kedua CAS1 dalam Complete () akan gagal karena * (d-> addr2)! = D . Tujuan utamanya adalah menghindari panggilan fungsi.
Contoh T1 = thread1, T2 = thread2:
sumber
addr2
mengandungd2->newval2
. Tapi, bagi saya sepertinya CAS1 di dalamComplete
hanya akan gagal, karena mengharapkan nilai lama menjadi deskriptord1
- tidak ada yang akan ditulis oleh T1. Baik?