Menguji kondisi lomba multi-utas

54

Membaca komentar untuk jawaban ini , khususnya:

Hanya karena Anda tidak dapat menulis tes tidak berarti itu tidak rusak. Perilaku tidak terdefinisi yang biasanya bekerja sesuai yang diharapkan (C dan C ++ penuh dengan itu), kondisi balapan, potensi pemesanan ulang karena model memori yang lemah ... - CodesInChaos 7 jam yang lalu

@CodesInChaos jika tidak dapat direproduksi maka kode yang ditulis untuk 'fix' juga tidak dapat diuji. Dan menempatkan kode yang belum diuji ke dalam hidup adalah kejahatan yang lebih buruk menurut saya - RhysW 5 jam yang lalu

... membuat saya bertanya-tanya apakah ada cara umum yang baik untuk secara konsisten memicu sangat jarang terjadi masalah produksi yang disebabkan oleh kondisi balapan dalam test case.

Dan Neely
sumber
1
langkah melalui (perakitan) instruksi dengan instruksi di kedua ujungnya
ratchet freak
1
Analisis statis sering dapat menunjukkan potensi UB, tidak jelas apakah ini dihitung sebagai uji coba
jk.
Maaf bertanya, tapi apa artinya 'UB'?
Doug
2
Pertanyaan yang bagus, saya akan menarik dalam melihat solusi potensial untuk ini.
RhysW
1
@Doug Undefined Behavior, yang dapat mencakup, tetapi tidak terbatas pada, kondisi lomba
jk.

Jawaban:

85

Setelah berkecimpung dalam bisnis gila ini sejak sekitar 1978, menghabiskan hampir semua waktu itu dalam komputasi waktu-nyata yang disematkan, bekerja multitasking, multithreaded, sistem multi-apa pun, kadang-kadang dengan beberapa prosesor fisik, mengejar lebih dari sekadar bagian ras yang adil. kondisi, pendapat saya yang dipertimbangkan adalah bahwa jawaban untuk pertanyaan Anda cukup sederhana.

Tidak.

Tidak ada cara umum yang baik untuk memicu kondisi balapan dalam pengujian.

Satu-satunya harapan Anda adalah mendesain mereka sepenuhnya dari sistem Anda.

Kapan dan jika Anda menemukan orang lain memasukkannya, Anda harus menaruhnya di sarang semut, dan kemudian mendesain ulang untuk menghilangkannya. Setelah Anda mendesain kecerobohannya (diucapkan f *** up) dari sistem Anda, Anda bisa melepaskannya dari semut. (Jika semut telah memakannya, hanya menyisakan tulang, pasang tanda bertuliskan "Inilah yang terjadi pada orang yang memasukkan kondisi ras ke dalam proyek XYZ!" Dan TINGGALKAN DIA.)

John R. Strohm
sumber
22
Saya sangat setuju. Dengan kata lain, ini sangat mirip dengan lelucon - Pasien: "Dokter, menyakitkan ketika saya melakukan ini ..." Dokter: "Kalau begitu berhenti melakukannya!"
Mark Rushakoff
Jawaban bagus. Jika sesuatu menyebabkan masalah yang tidak dapat dites, coba untuk mengatasinya untuk memulai, hindari masalah sama sekali!
RhysW
Satu-satunya pertanyaan saya adalah: Seberapa besar sarang semut yang harus saya gunakan? (+1 BTW).
Peter K.
15
+1 untuk pengucapan faux pas yang benar . (Dan sisanya dari jawabannya.)
Blrfl
1
@PeterK., Ini adalah salah satu dari beberapa kasus dalam pengembangan perangkat lunak, bersama dengan monitor, RAM, dan disk drive, di mana lebih besar IS yang lebih baik.
John R. Strohm
16

Jika Anda berada di rantai alat ms. Penelitian Ms telah menciptakan alat yang akan memaksa interlevings baru untuk setiap lari dan dapat diciptakan kembali gagal menjalankan catur yang disebut .

di sini adalah video yang menunjukkan itu digunakan.

memutarkan lagi
sumber
5
Itu terlihat mengesankan; Saya harus menemukan waktu untuk mencobanya di beberapa titik.
Dan Neely
16

Alat terbaik yang saya tahu untuk masalah seperti ini adalah perpanjangan Valgrind yang disebut Helgrind .

Pada dasarnya Valgrind mensimulasikan prosesor virtual dan menjalankan biner Anda (tidak dimodifikasi) di atasnya, sehingga dapat memeriksa setiap akses tunggal ke memori. Menggunakan kerangka kerja itu, sistem arloji Helgrind menyerukan untuk menyimpulkan ketika akses ke variabel bersama tidak dilindungi dengan baik oleh mekanisme saling pengecualian. Dengan begitu ia dapat mendeteksi kondisi ras teoretis bahkan jika itu belum benar-benar terjadi.

Intel menjual alat yang sangat mirip yang disebut Intel Inspector .

Alat-alat ini memberikan hasil yang bagus tetapi program Anda akan jauh lebih lambat selama analisis.

Julien
sumber
1
apakah Valgrind masih merupakan alat * nix saja?
Dan Neely
1
Ya, Linux, MacOSX, android dan beberapa BSD: valgrind.org/info/platforms.html
Julien
1
ThreadSanitizer adalah alat serupa. Ini bekerja secara berbeda dari Helgrind, yang memberikan keuntungan lebih cepat, tetapi membutuhkan integrasi ke dalam rantai alat.
Sebastian Redl
7

Mengekspos bug multi-threading membutuhkan pemaksaan utas eksekusi yang berbeda untuk melakukan langkah-langkah mereka dalam urutan tertentu. Biasanya ini sulit dilakukan tanpa debugging manual atau memanipulasi kode untuk mendapatkan semacam "pegangan" untuk mengontrol interleaving ini. Tetapi mengubah kode yang berperilaku tak terduga seringkali akan memengaruhi ketidakpastian itu, jadi ini sulit untuk diotomatisasi.

Trik yang bagus dijelaskan oleh Jaroslav Tulach dalam Praktis Desain API : jika Anda memiliki pernyataan logging dalam kode yang dipertanyakan, memanipulasi konsumen dari pernyataan logging tersebut (misalnya terminal pseudo-disuntikkan) sehingga menerima pesan log individu dalam suatu tertentu memesan berdasarkan konten mereka. Ini memungkinkan Anda untuk mengontrol interleaving langkah-langkah di utas yang berbeda tanpa harus menambahkan apa pun ke kode produksi yang belum ada di sana.

Kilian Foth
sumber
2
Saya telah melakukan hal yang sama sebelum menggunakan repositori yang disuntikkan untuk tidur utas yang menyebutnya dalam perintah khusus untuk memaksa interleave yang saya inginkan. Setelah kode tertulis yang melakukannya, saya cenderung memberi +1 @ John jawaban di atas. Serius, hal ini sangat menyakitkan untuk dipekerjakan dengan benar, dan masih hanya memberikan jaminan tebakan terbaik karena mungkin ada interleaf yang sedikit berbeda dengan hasil yang berbeda; pendekatan yang lebih baik adalah dengan hanya menghilangkan semua kondisi balapan yang mungkin melalui analisis statis dan atau menyisir kode dengan hati-hati untuk setiap dan semua negara yang dibagikan
Jimmy Hoffa
6

Tidak ada cara untuk benar-benar memastikan berbagai jenis perilaku yang tidak terdefinisi (dalam kondisi ras tertentu) tidak ada.

Namun, ada sejumlah alat yang menunjukkan sejumlah situasi seperti itu. Anda mungkin dapat membuktikan bahwa ada masalah saat ini dengan alat tersebut, meskipun Anda tidak dapat membuktikan bahwa perbaikan Anda valid.

Beberapa alat menarik untuk tujuan ini:

Valgrind adalah pemeriksa memori. Ia menemukan kebocoran memori, pembacaan memori yang tidak diinisialisasi, penggunaan pointer menggantung dan akses di luar batas.

Helgrind adalah pemeriksa keamanan utas. Ia menemukan kondisi balapan.

Keduanya bekerja dengan instrumentasi dinamis, yaitu mereka mengambil program Anda apa adanya dan menjalankannya dalam lingkungan yang tervirtualisasi. Ini membuat mereka tidak mengganggu, tetapi lambat.

UBSan adalah pemeriksa perilaku yang tidak ditentukan. Ia menemukan berbagai kasus perilaku tidak terdefinisi C dan C ++, seperti integer overflows, out-of-range shift dan hal-hal serupa.

MSan adalah pemeriksa memori. Ini memiliki tujuan yang sama dengan Valgrind.

TSan adalah pemeriksa keamanan utas. Ini memiliki tujuan yang sama dengan Helgrind.

Ketiganya dibangun ke dalam kompiler Dentang dan menghasilkan kode pada waktu kompilasi. Ini berarti bahwa Anda perlu mengintegrasikan mereka ke dalam proses build Anda (khususnya, Anda harus mengkompilasi dengan Dentang), yang membuat mereka jauh lebih sulit untuk diatur daripada * grind, tetapi di sisi lain mereka memiliki overhead runtime yang jauh lebih rendah.

Semua alat yang saya daftarkan berfungsi di Linux dan beberapa di MacOS. Saya belum berpikir ada pekerjaan di Windows andal.

Sebastian Redl
sumber
1

Tampaknya sebagian besar jawaban di sini keliru dengan pertanyaan ini sebagai "bagaimana cara saya mendeteksi kondisi lomba secara otomatis?" ketika pertanyaannya adalah "bagaimana cara mereproduksi kondisi balapan dalam pengujian saat saya menemukannya?"

Cara melakukannya adalah dengan memperkenalkan sinkronisasi dalam kode Anda yang hanya digunakan untuk pengujian. Misalnya, jika kondisi balapan terjadi ketika Peristiwa X terjadi di antara Peristiwa A dan Peristiwa B, maka untuk menguji aplikasi Anda, tulis beberapa kode yang menunggu Peristiwa X terjadi setelah Peristiwa A terjadi. Anda mungkin perlu beberapa cara agar tes Anda berbicara dengan aplikasi Anda untuk memberi tahu ("hei saya sedang menguji hal ini, jadi tunggu acara ini di lokasi ini").

Saya menggunakan node.js dan mongo, di mana beberapa tindakan melibatkan pembuatan data yang konsisten dalam beberapa koleksi. Dalam kasus ini, pengujian unit saya akan melakukan panggilan ke aplikasi untuk mengatakan "mengatur tunggu untuk Acara X", dan setelah aplikasi mengaturnya, tes untuk acara X akan berjalan, dan tes selanjutnya akan memberi tahu aplikasi ("saya sudah selesai dengan menunggu Acara X") sehingga sisa tes akan berjalan normal.

Jawabannya di sini menjelaskan hal semacam ini secara terperinci dalam konteks python: https://stackoverflow.com/questions/19602535/how-can-i-reproduce-the-race-conditions-in-this-python-code- andal

BT
sumber