Pertanyaan Apa itu kondisi balapan?


Saat menulis aplikasi multi-berulir, salah satu masalah paling umum yang dialami adalah kondisi balapan.

Pertanyaan saya kepada komunitas adalah:

Apa itu kondisi balapan? Bagaimana Anda mendeteksi mereka? Bagaimana Anda mengatasinya? Akhirnya, bagaimana Anda mencegahnya terjadi?


736
2017-08-29 15:55


asal


Jawaban:


Kondisi balapan terjadi ketika dua atau lebih untaian dapat mengakses data bersama dan mereka mencoba untuk mengubahnya pada saat yang bersamaan. Karena algoritma penjadwalan thread dapat bertukar antara utas kapan saja, Anda tidak tahu urutan di mana utas akan mencoba mengakses data bersama. Oleh karena itu, hasil dari perubahan data tergantung pada algoritma penjadwalan thread, yaitu kedua benang "berlomba" untuk mengakses / mengubah data.

Masalah sering terjadi ketika satu thread melakukan "check-then-act" (misalnya "cek" jika nilainya X, kemudian "bertindak" untuk melakukan sesuatu yang bergantung pada nilai menjadi X) dan utas lainnya melakukan sesuatu untuk nilai dalam antara "cek" dan "tindakan". Misalnya:

if (x == 5) // The "Check"
{
   y = x * 2; // The "Act"

   // If another thread changed x in between "if (x == 5)" and "y = x * 2" above,
   // y will not be equal to 10.
}

Intinya, y bisa 10, atau bisa juga apa saja, tergantung apakah ada utas yang berubah x di antara cek dan bertindak. Anda tidak memiliki cara mengetahui yang nyata.

Untuk mencegah kondisi balapan terjadi, Anda biasanya akan mengunci kunci di sekitar data bersama untuk memastikan hanya satu utas dapat mengakses data pada satu waktu. Ini berarti sesuatu seperti ini:

// Obtain lock for x
if (x == 5)
{
   y = x * 2; // Now, nothing can change x until the lock is released. 
              // Therefore y = 10
}
// release lock for x

917
2017-08-29 16:05



Suatu "kondisi balapan" ada ketika kode multithreaded (atau paralel) yang akan mengakses sumber daya bersama dapat melakukannya sedemikian rupa sehingga menyebabkan hasil yang tidak diharapkan.

Ambil contoh ini:

for ( int i = 0; i < 10000000; i++ )
{
   x = x + 1; 
}

Jika Anda memiliki 5 thread mengeksekusi kode ini sekaligus, nilai x TIDAK AKAN berakhir menjadi 50.000.000. Sebenarnya akan bervariasi dengan setiap run.

Ini karena, agar setiap utas menambah nilai x, mereka harus melakukan hal berikut: (disederhanakan, jelas)

Ambil nilai x
Tambahkan 1 ke nilai ini
Simpan nilai ini ke x

Setiap utas dapat berada pada langkah apa pun dalam proses ini kapan saja, dan mereka dapat saling menginjak ketika sumber daya bersama dilibatkan. Keadaan x dapat diubah oleh utas lain selama waktu antara x sedang dibaca dan saat ditulis kembali.

Katakanlah sebuah utas mengambil nilai x, tetapi belum menyimpannya. Utas lain juga dapat mengambil sama nilai x (karena belum ada benang yang mengubahnya) dan kemudian keduanya akan menyimpan sama nilai (x + 1) kembali x!

Contoh:

Thread 1: membaca x, nilai adalah 7
Thread 1: tambahkan 1 ke x, nilai sekarang 8
Thread 2: membaca x, nilainya 7
Thread 1: menyimpan 8 dalam x
Thread 2: menambahkan 1 ke x, nilai sekarang 8
Thread 2: toko 8 dalam x

Kondisi lomba dapat dihindari dengan menggunakan semacam mengunci mekanisme sebelum kode yang mengakses sumber yang dibagikan:

for ( int i = 0; i < 10000000; i++ )
{
   //lock x
   x = x + 1; 
   //unlock x
}

Di sini, jawabannya muncul 50.000.000 setiap waktu.

Untuk lebih lanjut tentang mengunci, cari: mutex, semaphore, bagian kritis, sumber daya bersama.


176
2017-08-29 17:01



Apa itu Kondisi Balapan?

Anda berencana untuk pergi ke bioskop jam 5 sore. Anda menanyakan tentang ketersediaan tiket pada pukul 4 sore. Perwakilan mengatakan bahwa mereka tersedia. Anda bersantai dan mencapai jendela tiket 5 menit sebelum pertunjukan. Saya yakin Anda bisa menebak apa yang terjadi: ini adalah rumah yang lengkap. Masalahnya di sini adalah durasi antara pemeriksaan dan tindakan. Anda bertanya pada 4 dan bertindak di 5. Sementara itu, orang lain meraih tiket. Itu adalah kondisi balapan - khususnya skenario "check-then-act" kondisi balapan.

Bagaimana Anda mendeteksi mereka?

Peninjauan kode agama, tes unit multi-berulir. Tidak ada jalan pintas. Ada beberapa plugin Eclipse yang muncul di sini, tetapi belum ada yang stabil.

Bagaimana Anda menangani dan mencegahnya?

Yang terbaik adalah membuat efek samping bebas dan fungsi tanpa negara, menggunakan immutable sebanyak mungkin. Tetapi itu tidak selalu mungkin. Jadi menggunakan java.util.concurrent.atomic, struktur data konkuren, sinkronisasi yang tepat, dan konkurensi berdasarkan aktor akan membantu.

Sumber daya terbaik untuk konkurensi adalah JCIP. Anda juga bisa mendapatkan lebih banyak perincian tentang penjelasan di atas di sini.


111
2017-10-04 21:20



Ada perbedaan teknis yang penting antara kondisi balapan dan ras data. Sebagian besar jawaban tampaknya membuat asumsi bahwa istilah-istilah ini setara, tetapi tidak.

Perlombaan data terjadi ketika 2 instruksi mengakses lokasi memori yang sama, setidaknya satu dari akses ini adalah menulis dan tidak ada terjadi sebelum memesan di antara akses ini. Sekarang apa yang terjadi sebelum memesan tunduk pada banyak perdebatan, tetapi secara umum ulock-lock berpasangan pada variabel kunci yang sama dan pasangan menunggu-sinyal pada variabel kondisi yang sama menginduksi terjadi sebelum pesanan.

Kondisi balapan adalah kesalahan semantik. Ini adalah cacat yang terjadi pada waktu atau urutan kejadian yang mengarah ke program yang salah tingkah laku.

Banyak kondisi ras dapat (dan sebenarnya) disebabkan oleh ras data, tetapi ini tidak diperlukan. Faktanya, ras data dan kondisi balapan bukanlah hal yang diperlukan, atau kondisi yang cukup untuk satu sama lain. Ini posting blog juga menjelaskan perbedaan dengan sangat baik, dengan contoh transaksi bank sederhana. Berikut ini sederhana lainnya contoh yang menjelaskan perbedaannya.

Sekarang setelah kami memahami terminologi, mari kita coba menjawab pertanyaan aslinya.

Mengingat bahwa kondisi ras adalah bug semantik, tidak ada cara umum untuk mendeteksi mereka. Ini karena tidak ada cara untuk memiliki oracle otomatis yang dapat membedakan perilaku program yang benar vs salah dalam kasus umum. Deteksi ras adalah masalah yang tidak dapat diputuskan.

Di sisi lain, ras data memiliki definisi yang tepat yang tidak selalu berhubungan dengan kebenaran, dan oleh karena itu orang dapat mendeteksi mereka. Ada banyak rasa detektor data ras (deteksi data ras statis / dinamis, deteksi ras data berbasis kuncian, pendeteksian ras berdasarkan data yang ada sebelum-sebelumnya, deteksi ras data hibrid). Detektor balap data dinamis yang canggih adalah ThreadSanitizer yang bekerja sangat baik dalam praktek.

Penanganan ras data secara umum memerlukan beberapa disiplin pemrograman untuk menginduksi yang terjadi sebelum tepi antara akses ke data bersama (baik selama pengembangan, atau setelah terdeteksi menggunakan alat yang disebutkan di atas). ini dapat dilakukan melalui kunci, variabel kondisi, semaphores, dll. Namun, seseorang juga dapat menggunakan paradigma pemrograman yang berbeda seperti pesan yang lewat (bukan memori bersama) yang menghindari ras data dengan konstruksi.


52
2017-08-29 08:45



Definisi semacam kanonik adalah "ketika dua utas mengakses lokasi yang sama di memori pada saat yang sama, dan setidaknya satu dari akses adalah tulisan"Dalam situasi ini," pembaca "thread mungkin mendapatkan nilai lama atau nilai baru, tergantung pada thread mana yang" memenangkan perlombaan. "Ini tidak selalu bug - pada kenyataannya, beberapa algoritma tingkat rendah yang sangat berbulu melakukan ini pada tujuan — tetapi umumnya harus dihindari. @Steve Gury memberi contoh yang baik tentang kapan itu mungkin menjadi masalah.


32
2017-08-29 16:21



Kondisi ras adalah sejenis bug, yang hanya terjadi pada kondisi temporal tertentu.

Contoh: Bayangkan Anda memiliki dua utas, A dan B.

Di Thread A:

if( object.a != 0 )
    object.avg = total / object.a

Di Thread B:

object.a = 0

Jika thread A didahului hanya setelah memeriksa objek itu. Tidak batal, B akan melakukannya a = 0, dan ketika thread A akan mendapatkan prosesor, ia akan melakukan "membagi dengan nol".

Bug ini hanya terjadi ketika thread A didahului tepat setelah pernyataan if, sangat jarang, tetapi bisa terjadi.


27
2017-08-29 16:03



Kondisi ras terjadi dalam aplikasi multi-threaded atau sistem multi-proses. Suatu kondisi balapan, pada dasarnya, adalah segala sesuatu yang membuat asumsi bahwa dua hal yang tidak dalam alur atau proses yang sama akan terjadi dalam urutan tertentu, tanpa mengambil langkah-langkah untuk memastikannya. Ini biasanya terjadi ketika dua utas menyampaikan pesan dengan menyetel dan memeriksa variabel anggota suatu kelas, keduanya dapat mengakses. Hampir selalu ada kondisi balapan ketika satu utas panggilan tidur untuk memberikan waktu untaian lain untuk menyelesaikan tugas (kecuali jika tidur dalam satu lingkaran, dengan beberapa mekanisme pemeriksaan).

Alat untuk mencegah kondisi balapan bergantung pada bahasa dan OS, tetapi beberapa komon adalah mutex, bagian penting, dan sinyal. Mutexes bagus ketika Anda ingin memastikan Anda satu-satunya yang melakukan sesuatu. Sinyal baik ketika Anda ingin memastikan orang lain selesai melakukan sesuatu. Meminimalkan sumber daya bersama juga dapat membantu mencegah perilaku yang tidak terduga

Mendeteksi kondisi balapan bisa sulit, tetapi ada beberapa tanda. Kode yang sangat bergantung pada tidur rentan terhadap kondisi balapan, jadi pertama-tama periksa panggilan untuk tidur dalam kode yang terpengaruh. Menambah tidur sangat lama juga dapat digunakan untuk debugging untuk mencoba dan memaksa urutan peristiwa tertentu. Ini dapat berguna untuk mereproduksi perilaku, melihat apakah Anda dapat membuatnya menghilang dengan mengubah waktu hal-hal, dan untuk solusi pengujian diberlakukan. Tidur harus dihapus setelah debugging.

Tanda tanda tangan bahwa seseorang memiliki kondisi balapan, adalah jika ada masalah yang hanya terjadi sebentar-sebentar pada beberapa mesin. Bug umum akan crash dan deadlock. Dengan penebangan, Anda harus dapat menemukan area yang terkena dampak dan kembali dari sana.


18
2017-08-29 16:12



Kondisi lomba tidak hanya terkait dengan perangkat lunak tetapi juga terkait dengan perangkat keras juga. Sebenarnya istilah itu awalnya diciptakan oleh industri perangkat keras.

Menurut wikipedia:

Istilah ini berasal dari ide dua sinyal saling berpacu untuk    mempengaruhi output terlebih dahulu.

Kondisi balapan di sirkuit logika:

enter image description here

Industri perangkat lunak mengambil istilah ini tanpa modifikasi, yang membuatnya sedikit sulit untuk dipahami.

Anda perlu melakukan beberapa penggantian untuk memetakannya ke dunia perangkat lunak:

  • "two signals" => "dua utas" / "dua proses"
  • "mempengaruhi output" => "mempengaruhi beberapa keadaan bersama"

Jadi kondisi balapan dalam industri perangkat lunak berarti "dua utas" / "dua proses" berpacu satu sama lain untuk "mempengaruhi beberapa keadaan bersama", dan hasil akhir dari keadaan bersama akan bergantung pada perbedaan waktu yang halus, yang dapat disebabkan oleh beberapa spesifik urutan peluncuran thread / proses, penjadwalan thread / proses, dll.


9
2017-08-04 03:57