การทดสอบสภาพการแข่งขันแบบมัลติเธรด


54

อ่านความคิดเห็นต่อคำตอบนี้โดยเฉพาะ:

เพียงเพราะคุณไม่สามารถเขียนการทดสอบไม่ได้หมายความว่ามันจะไม่พัง พฤติกรรมที่ไม่ได้กำหนดซึ่งมักจะเกิดขึ้นในการทำงานตามที่คาดไว้ (C และ C ++ เต็มไปด้วยนั้น) สภาพการแข่งขันการจัดเรียงใหม่ที่อาจเกิดขึ้นเนื่องจากรุ่นหน่วยความจำที่อ่อนแอ ... - CodesInChaos 7 ชั่วโมงที่ผ่านมา

@CodesInChaos หากไม่สามารถทำซ้ำรหัสที่เขียนไปยัง 'แก้ไข' ไม่สามารถทดสอบได้เช่นกัน และการใส่รหัสที่ยังไม่ได้ทดสอบเข้าสู่การถ่ายทอดสดเป็นอาชญากรรมที่แย่กว่าในความคิดของฉัน - RhysW 5 ชั่วโมงที่แล้ว

... ฉันสงสัยหรือไม่ว่ามีวิธีการทั่วไปที่ดีในการทำให้เกิดปัญหาการผลิตอย่างต่อเนื่องไม่บ่อยนักซึ่งเกิดจากสภาพการแข่งขันในกรณีทดสอบ


1
การสอนแบบทีละขั้นตอนโดยการสอนที่ปลายทั้งสอง
วงล้อประหลาด

1
การวิเคราะห์เชิงสถิตสามารถแสดง UB ที่อาจเกิดขึ้นได้ แต่ไม่ชัดเจนหากนับเป็นทดสอบแม้ว่า
jk

ขออภัยที่จะถาม แต่ 'UB' หมายถึงอะไร
Doug

2
คำถามที่ดีฉันจะน่าสนใจในการดูวิธีแก้ปัญหาที่อาจเกิดขึ้น
RhysW

1
@Doug พฤติกรรมที่ไม่ได้กำหนดซึ่งอาจรวมถึง แต่ไม่ จำกัด เพียงเงื่อนไขการแข่งขัน
jk

คำตอบ:


85

หลังจากอยู่ในธุรกิจที่บ้าคลั่งมาตั้งแต่ปี 2521 การใช้เวลาเกือบทั้งหมดในการประมวลผลแบบเรียลไทม์แบบฝังการทำงานแบบมัลติทาสกิ้งแบบมัลติเธรดแบบมัลติเธรดบางครั้งกับตัวประมวลผลทางกายภาพหลายครั้ง เงื่อนไขความเห็นที่ฉันพิจารณาคือคำตอบสำหรับคำถามของคุณค่อนข้างง่าย

เลขที่

ไม่มีวิธีทั่วไปที่ดีในการเรียกสภาพการแข่งขันในการทดสอบ

ความหวังเดียวของคุณคือการออกแบบพวกเขาออกจากระบบของคุณอย่างสมบูรณ์

เมื่อใดและถ้าคุณพบว่ามีคนยัดไส้เขาไว้คุณควรแบ่งเขาออกจากเนินแล้วจึงออกแบบใหม่เพื่อกำจัดมัน หลังจากที่คุณออกแบบ faux pas ของเขาออกมาจากระบบของคุณคุณสามารถปล่อยเขาออกจากมดได้ (หากมดกินเขาไปแล้วเหลือเพียงกระดูกเท่านั้นให้ใส่เครื่องหมายบอกว่า "นี่คือสิ่งที่เกิดขึ้นกับคนที่ใส่เงื่อนไขการแข่งขันลงในโครงการ XYZ!" และออกจากที่นั่น)


22
ฉันเห็นด้วยอย่างยิ่ง พูดอีกอย่างนี้ก็เหมือนเรื่องตลก - ผู้ป่วย: "หมอมันเจ็บเมื่อฉันทำอย่างนี้ ... " หมอ: "แล้วหยุดทำมัน!"
Mark Rushakoff

คำตอบที่ดี หากมีสิ่งใดที่ทำให้เกิดปัญหาที่ไม่สามารถทดสอบได้ให้ลองแก้ปัญหาโดยเริ่มจากหลีกเลี่ยงปัญหาทั้งหมด!
RhysW

คำถามเดียวของฉันคือฉันควรใช้ anthill ขนาดไหน? (+1 BTW)
ปีเตอร์เค

15
+1 สำหรับการออกเสียงที่ถูกต้องของเทรนด์ (และคำตอบที่เหลือ)
Blrfl

1
@PeterK. นี้เป็นหนึ่งในกรณีไม่กี่คนในการพัฒนาซอฟแวร์พร้อมกับจอภาพ, RAM และดิสก์ไดรฟ์ที่มีขนาดใหญ่เป็นที่ดีกว่า
John R. Strohm

16

หากคุณอยู่ในห่วงโซ่เครื่องมือ ms การวิจัยนางสาวได้สร้างเครื่องมือที่จะบังคับให้มีการให้บริการใหม่สำหรับการวิ่งแต่ละครั้งและสามารถสร้างการเรียกใช้ที่ล้มเหลวในการเรียกหมากรุกขึ้นใหม่

นี่คือวิดีโอที่แสดงว่ามีการใช้งานอยู่


5
ดูน่าประทับใจ ฉันจะต้องหาเวลาลองดูซักครั้ง
Dan Neely

16

เครื่องมือที่ดีที่สุดฉันรู้ว่าการเรียงลำดับของปัญหาเหล่านี้เป็นส่วนขยายของ Valgrind เรียกHelgrind

โดยพื้นฐานแล้ว Valgrind จะจำลองตัวประมวลผลเสมือนและรันไบนารีของคุณ (ไม่ได้แก้ไข) ที่ด้านบนของมันเพื่อให้สามารถตรวจสอบทุกการเข้าถึงหน่วยความจำ การใช้เฟรมเวิร์กนั้นระบบตรวจสอบของ Helgrind จะเรียกการอนุมานเมื่อการเข้าถึงตัวแปรที่แชร์นั้นไม่ได้รับการปกป้องอย่างถูกต้องโดยกลไกการยกเว้นซึ่งกันและกัน ด้วยวิธีนี้มันสามารถตรวจจับสภาพการแข่งขันทางทฤษฎีแม้ว่ามันจะไม่ได้เกิดขึ้นจริง

อินเทลขายเครื่องมือที่คล้ายกันมากเรียกว่าIntel สารวัตร

เครื่องมือเหล่านี้ให้ผลลัพธ์ที่ยอดเยี่ยม แต่โปรแกรมของคุณจะช้าลงอย่างมากในระหว่างการวิเคราะห์


1
Valgrind ยังคงเป็นเพียงเครื่องมือ * nix เท่านั้นหรือไม่
Dan Neely

1
ใช่ Linux, MacOSX, android และ BSD บางส่วน: valgrind.org/info/platforms.html
Julien

1
ThreadSanitizer เป็นเครื่องมือที่คล้ายกัน มันทำงานแตกต่างจาก Helgrind ซึ่งให้ข้อดีของการทำงานเร็วกว่ามาก แต่ต้องการการรวมเข้ากับ toolchain
เซบาสเตียนเรดล

7

การเปิดเผยบั๊กแบบมัลติเธรดจำเป็นต้องบังคับเธรดที่แตกต่างกันของการดำเนินการเพื่อทำตามขั้นตอนตามลำดับ interleaved เฉพาะ โดยทั่วไปแล้วการทำเช่นนี้จะทำได้ยากโดยไม่ต้องทำการดีบั๊กหรือใช้รหัสเพื่อให้ได้ "จัดการ" บางอย่างเพื่อควบคุมการสอดแทรกนี้ แต่การเปลี่ยนรหัสที่ไม่สามารถคาดการณ์ได้มักจะส่งผลต่อความไม่แน่นอนดังนั้นจึงเป็นการยากที่จะทำให้เป็นอัตโนมัติ

เคล็ดลับที่ดีถูกอธิบายโดย Jaroslav Tulach ในการออกแบบ APIในทางปฏิบัติ : หากคุณมีการบันทึกคำสั่งในรหัสภายใต้คำถามให้จัดการกับผู้บริโภคของคำสั่งการบันทึกเหล่านั้น (เช่นเทอร์มินัลหลอกเทียม) เพื่อให้ยอมรับข้อความบันทึกแต่ละรายการ สั่งซื้อตามเนื้อหาของพวกเขา สิ่งนี้ช่วยให้คุณควบคุมการแทรกขั้นตอนในเธรดต่าง ๆ โดยไม่ต้องเพิ่มอะไรลงในโค้ดการผลิตที่ยังไม่มี


2
ฉันได้ทำที่คล้ายกันก่อนที่จะใช้พื้นที่เก็บข้อมูลของ injected เพื่อนอนกระทู้ที่เรียกว่าในคำสั่งเฉพาะเพื่อบังคับให้ interleave ฉันต้องการ มีรหัสเป็นลายลักษณ์อักษรที่ทำมันฉันมีแนวโน้มที่จะ +1 คำตอบของจอห์นข้างต้น อย่างจริงจังสิ่งนี้เจ็บปวดอย่างมากที่จะใช้อย่างถูกต้องและยังคงรับประกันการเดาที่ดีที่สุดเท่านั้นเนื่องจากอาจมีการแทรกสอดที่แตกต่างกันเล็กน้อยกับผลลัพธ์ที่แตกต่างกัน วิธีที่ดีกว่าคือการกำจัดสภาพการแข่งขันที่เป็นไปได้ทั้งหมดผ่านการวิเคราะห์แบบคงที่และหรือการใช้รหัสอย่างระมัดระวังสำหรับสถานะที่ใช้ร่วมกันทั้งหมด
Jimmy Hoffa

6

ไม่มีวิธีใดที่จะแน่ใจได้ว่าพฤติกรรมที่ไม่ได้กำหนดประเภทต่างๆ (โดยเฉพาะในสภาพการแข่งขัน) ไม่มีอยู่จริง

อย่างไรก็ตามมีเครื่องมือจำนวนหนึ่งที่แสดงสถานการณ์ดังกล่าวจำนวนมาก คุณอาจพิสูจน์ได้ว่ามีปัญหาเกิดขึ้นกับเครื่องมือดังกล่าวแม้ว่าคุณจะไม่สามารถพิสูจน์ได้ว่าการแก้ไขของคุณนั้นถูกต้อง

เครื่องมือที่น่าสนใจสำหรับวัตถุประสงค์นี้:

Valgrind เป็นเครื่องมือตรวจสอบหน่วยความจำ พบการรั่วไหลของหน่วยความจำอ่านหน่วยความจำที่ไม่ได้กำหนดค่าเริ่มต้นการใช้พอยน์เตอร์ห้อยต่องแต่งและการเข้าถึงนอกขอบเขต

Helgrind เป็นตัวตรวจสอบความปลอดภัยของเธรด พบสภาพการแข่งขัน

ทั้งทำงานโดยการใช้เครื่องมือแบบไดนามิกนั่นคือพวกเขาใช้โปรแกรมของคุณตามสภาพและดำเนินการในสภาพแวดล้อมเสมือนจริง สิ่งนี้ทำให้พวกเขาไม่ล่วงล้ำ แต่ช้า

UBSan เป็นเครื่องมือตรวจสอบพฤติกรรมที่ไม่ได้กำหนด พบกรณีต่าง ๆ ของพฤติกรรมที่ไม่ได้กำหนด C และ C ++ เช่นล้นจำนวนเต็มกะนอกช่วงและสิ่งที่คล้ายกัน

MSan เป็นตัวตรวจสอบหน่วยความจำ มันมีเป้าหมายคล้าย ๆ กับ Valgrind

TSan เป็นตัวตรวจสอบความปลอดภัยของเธรด มันมีเป้าหมายที่คล้ายกันเป็น Helgrind

ทั้งสามถูกสร้างขึ้นในคอมไพเลอร์เสียงดังกราวและสร้างรหัสในเวลารวบรวม ซึ่งหมายความว่าคุณต้องรวมพวกเขาเข้ากับกระบวนการสร้างของคุณ (โดยเฉพาะคุณต้องคอมไพล์ด้วย Clang) ซึ่งทำให้ยากต่อการตั้งค่าเริ่มต้นมากกว่า * ฝน แต่ในทางกลับกันพวกเขามีค่าใช้จ่ายรันไทม์ต่ำกว่ามาก

เครื่องมือทั้งหมดที่ฉันระบุไว้ทำงานบน Linux และบางส่วนใน MacOS ฉันไม่คิดว่าจะทำงานบน Windows ได้อย่างน่าเชื่อถือ


1

ดูเหมือนว่าคำตอบส่วนใหญ่ที่นี่ผิดพลาดคำถามนี้เป็น "ฉันจะตรวจสอบสภาพการแข่งขันโดยอัตโนมัติได้อย่างไร" เมื่อคำถามคือ "ฉันจะจำลองสภาพการแข่งขันในการทดสอบได้อย่างไรเมื่อพบพวกเขา"

วิธีที่จะทำคือการแนะนำการซิงโครไนซ์ในรหัสของคุณที่ใช้สำหรับการทดสอบเท่านั้น ตัวอย่างเช่นหากสภาพการแย่งชิงเกิดขึ้นเมื่อเหตุการณ์ X เกิดขึ้นระหว่างกิจกรรม A และเหตุการณ์ B ดังนั้นสำหรับการทดสอบแอปพลิเคชันของคุณให้เขียนโค้ดบางอย่างที่รอให้เหตุการณ์ X เกิดขึ้นหลังจากเหตุการณ์ A เกิดขึ้น คุณอาจต้องใช้วิธีการทดสอบเพื่อพูดคุยกับแอปพลิเคชันของคุณเพื่อบอก ("เฮ้ฉันกำลังทดสอบสิ่งนี้ดังนั้นให้รอเหตุการณ์นี้ที่สถานที่นี้")

ฉันกำลังใช้ node.js และ Mongo ซึ่งการกระทำบางอย่างเกี่ยวข้องกับการสร้างข้อมูลที่สอดคล้องกันในหลายคอลเลกชัน ในกรณีเหล่านี้การทดสอบหน่วยของฉันจะโทรไปยังแอปพลิเคชันเพื่อบอกว่า "ตั้งค่าการรอ Event X" และเมื่อแอปพลิเคชันได้ตั้งค่าแล้วการทดสอบสำหรับกิจกรรม X จะทำงานและการทดสอบจะบอกในภายหลัง แอปพลิเคชัน ("ฉันเสร็จสิ้นการรอ Event X") ดังนั้นการทดสอบที่เหลือจะทำงานตามปกติ

คำตอบที่นี่จะอธิบายรายละเอียดของสิ่งนี้ในบริบทของ python: https://stackoverflow.com/questions/19602535/how-can-i-reproduce-the-race-conditions-in-this-python-code-thailand อย่างน่าเชื่อถือ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.