Perbandingan atom, Multi-Prosesor, C/C++ (Linux)

Saya memiliki variabel di memori bersama x pada sistem multi-prosesor.

void MyFunction(volatile int* x) {
  if (*x != 0) {
     // do something
  }
}

Proses lain (mungkin pada prosesor berbeda) akan menulis ke x menggunakan operasi atom bawaan gcc seperti __sync_bool_compare_and_swap dll.

Saya rasa saya mengalami beberapa masalah konkurensi cache yang terkadang memerlukan sedikit waktu sebelum x akhirnya diperbarui dengan nilai baru.

Yang saya inginkan adalah semacam atom_bandingkan (tanpa pertukaran), jika hal seperti itu ada? Atau "pembacaan atom". Apa cara tercepat untuk melakukan ini? (menghindari mutex, kunci, dll.)

Terima kasih

Sunting:

Saya baru menyadari bahwa solusi yang agak hackish adalah dengan menggunakan __sync_val_compare_and_swap dengan nilai yang saya tahu tidak akan pernah bisa terjadi. Apakah hal itu akan menyelesaikan masalah? (Apakah ada cara yang lebih bersih?)


person Switch    schedule 30.06.2012    source sumber
comment
Sekadar informasi, volatil sebenarnya tidak akan melakukan semua yang Anda inginkan untuk program multithread. Lihat: stackoverflow.com/questions/2484980/   -  person argentage    schedule 30.06.2012


Jawaban (3)


Standar C baru, C11, memiliki _Atomic tipe data dan operasi untuk menangani hal ini. Standar ini belum diterapkan, tetapi gcc dan clang sudah mendekatinya, mereka sudah mengimplementasikan fungsinya. Dan sebenarnya fungsi __sync_bool_compare_and_swap adalah bagian darinya. Saya telah menggabungkannya ke dalam kumpulan header di P99 yang memungkinkan Anda memprogram sudah dengan antarmuka C11.

Fungsi C11 untuk melakukan apa yang Anda inginkan adalah atomic_load atau jika Anda memiliki persyaratan khusus untuk koherensi atomic_load_explicit. Dan tidak mengherankan, seperti yang Anda duga, P99 memetakannya di __sync_val_compare_and_swap(&x, 0, 0). Kemudian jika Anda melihat ke dalam assembler yang dihasilkan pada sebagian besar arsitektur, ini hanya akan diterjemahkan dalam operasi pemuatan sederhana dalam kasus x menjadi int. Namun hal ini tidak dijamin oleh bahasanya, terserah kepada kompiler untuk mengetahui hal-hal tersebut dan untuk mensintesis instruksi yang dijamin bersifat atomik.

person Jens Gustedt    schedule 30.06.2012

Apa cara tercepat untuk melakukan ini? (menghindari mutex, kunci, dll.)

Saya cukup yakin Anda tidak ingin menghindari mutex. futex linux memungkinkan Anda untuk memanfaatkan kebaikan perbandingan-dan-swap (sebagian besar waktu) sambil menjaga semantik mutex klasik ('swap' yang terjadi adalah salah satu mutex, bukan kode/data yang dilindungi olehnya). Saya sangat menyarankan agar Anda mencobanya dan membuat profil solusinya (perf, oprofile, VTune, dll) untuk melihat apakah kemacetan Anda benar-benar terkait dengan mekanisme penguncian itu sendiri dan bukan hal-hal seperti pemanfaatan cache, throughput memori, siklus CPU, akses IO, jarak jauh -akses memori node, dll.

Saya rasa saya mengalami beberapa masalah konkurensi cache yang terkadang memerlukan sedikit waktu sebelum x akhirnya diperbarui dengan nilai baru.

Baiklah, anggaplah Anda benar-benar memiliki kebutuhan untuk berinteraksi antar prosesor dan Anda telah mengukur latensi yang diperoleh dari futex dan Anda telah memutuskan bahwa hal tersebut tidak akan memenuhi kebutuhan aplikasi Anda. Jadi, jika itu masalahnya, cara yang relatif masuk akal untuk melanjutkan adalah seperti ini: buat array bilangan bulat 32-bit, yang diisi dengan jarak yang lebih besar atau sama dengan ukuran baris cache target Anda. Gunakan ukuran CPU dan baris cache yang sedang dijalankan sebagai indeks ke dalam nilai sebenarnya dalam daftar ini (jadi jika baris cache Anda adalah 64 byte, Anda akan menskalakan CPU# sebanyak 16 untuk melompati padding). Anda harus menulis nilai-nilai ini hanya dari CPU yang sesuai dan Anda dapat melakukan polling dari CPU lain (mungkin harus memanggil salah satu instruksi "jeda" CPU Anda di badan tunggu-sibuk). Ini akan menjadi mekanisme yang efektif untuk memeriksa apakah thread eksekusi yang berbeda telah mencapai/memenuhi kondisi tertentu.

Saya harus menambahkan bahwa ini hampir pasti akan berhasil (secara efektif memperdagangkan efisiensi CPU untuk kemungkinan latensi yang lebih rendah) tetapi tetap merupakan solusi yang sangat rapuh untuk semua kecuali perangkat keras yang sangat tertentu.

person Brian Cain    schedule 30.06.2012
comment
tidak ada mutex yang berlebihan, bahkan di linux. C modern memiliki jawabannya, yang lebih mendekati perkiraan Switch daripada yang Anda kira. - person Jens Gustedt; 30.06.2012

Yang saya inginkan adalah semacam atom_bandingkan (tanpa pertukaran), jika hal seperti itu ada? Atau "pembacaan atom".

Perbandingan sudah bersifat atomik. Ini adalah bacaan tunggal.

Jika latensi antar prosesor sudah seburuk itu, sepertinya kode Anda akan mendapat manfaat jika sedikit dipisahkan. Yaitu. pisahkan sedikit ketergantungannya sehingga Anda tidak bergantung pada komunikasi semacam ini di loop batin Anda.

person Adam    schedule 30.06.2012
comment
tidak, tidak ada jaminan bahwa satu operasi beban pada level C diterjemahkan hanya dalam satu pembacaan tingkat rendah. Pada sebagian besar arsitektur, ini berlaku untuk int, tetapi tidak ada jaminan untuk itu. - person Jens Gustedt; 30.06.2012