ฉันมักจะพบว่ามีการใช้คำเหล่านี้ในบริบทของการเขียนโปรแกรมพร้อมกัน เหมือนกันหรือต่างกัน?
ฉันมักจะพบว่ามีการใช้คำเหล่านี้ในบริบทของการเขียนโปรแกรมพร้อมกัน เหมือนกันหรือต่างกัน?
คำตอบ:
ไม่พวกเขาไม่ใช่สิ่งเดียวกัน พวกเขาไม่ใช่ส่วนย่อยของกันและกัน นอกจากนี้ยังไม่จำเป็นหรือเป็นเงื่อนไขที่เพียงพอสำหรับกันและกัน
คำจำกัดความของการแข่งขันข้อมูลค่อนข้างชัดเจนดังนั้นการค้นพบจึงสามารถทำได้โดยอัตโนมัติ การแย่งชิงข้อมูลเกิดขึ้นเมื่อ 2 คำสั่งจากเธรดที่แตกต่างกันเข้าถึงตำแหน่งหน่วยความจำเดียวกันอย่างน้อยหนึ่งในการเข้าถึงเหล่านี้คือการเขียนและไม่มีการซิงโครไนซ์ที่กำหนดลำดับใด ๆระหว่างการเข้าถึงเหล่านี้
เงื่อนไขการแข่งขันเป็นข้อผิดพลาดทางความหมาย เป็นข้อบกพร่องที่เกิดขึ้นในจังหวะเวลาหรือลำดับเหตุการณ์ที่นำไปสู่พฤติกรรมของโปรแกรมที่ผิดพลาด เงื่อนไขการแข่งขันหลายอย่างอาจเกิดจากการแข่งขันข้อมูล แต่ไม่จำเป็น
พิจารณาตัวอย่างง่ายๆต่อไปนี้โดยที่ x เป็นตัวแปรที่ใช้ร่วมกัน:
Thread 1 Thread 2
lock(l) lock(l)
x=1 x=2
unlock(l) unlock(l)
ในตัวอย่างนี้การเขียนไปยัง x จากเธรด 1 และ 2 ได้รับการป้องกันโดยการล็อกดังนั้นจึงมักเกิดขึ้นในบางลำดับที่บังคับใช้โดยลำดับที่ได้รับการล็อกที่รันไทม์ นั่นคือปรมาณูของการเขียนไม่สามารถหักได้ มักจะเกิดขึ้นก่อนความสัมพันธ์ระหว่างทั้งสองจะเขียนในการดำเนินการใด ๆ เราไม่สามารถรู้ได้ว่าการเขียนใดเกิดขึ้นก่อนคนอื่น ๆ
ไม่มีลำดับคงที่ระหว่างการเขียนเนื่องจากการล็อกไม่สามารถจัดเตรียมสิ่งนี้ได้ หากความถูกต้องของโปรแกรมถูกทำลายให้พูดว่าเมื่อเขียนถึง x โดยเธรด 2 แล้วตามด้วยการเขียนถึง x ในเธรด 1 แสดงว่ามีเงื่อนไขการแข่งขันแม้ว่าในทางเทคนิคจะไม่มีการแย่งข้อมูล
การตรวจจับสภาพการแข่งขันมีประโยชน์มากกว่าการแข่งขันข้อมูล อย่างไรก็ตามนี่เป็นเรื่องยากมากที่จะบรรลุ
การสร้างตัวอย่างย้อนกลับก็เป็นเรื่องเล็กน้อยเช่นกัน นี้บล็อกโพสต์ยังได้อธิบายถึงความแตกต่างได้เป็นอย่างดีกับตัวอย่างการทำธุรกรรมธนาคารที่เรียบง่าย
ตามวิกิพีเดียคำว่า "สภาพการแข่งขัน" ถูกใช้มาตั้งแต่สมัยของประตูลอจิกอิเล็กทรอนิกส์ครั้งแรก ในบริบทของ Java เงื่อนไขการแย่งชิงสามารถเกี่ยวข้องกับทรัพยากรใด ๆ เช่นไฟล์การเชื่อมต่อเครือข่ายเธรดจากเธรดพูลเป็นต้น
คำว่า "การแข่งขันข้อมูล" ถูกสงวนไว้สำหรับการที่ดีที่สุดที่เฉพาะเจาะจงของความหมายที่กำหนดโดยJLS
กรณีที่น่าสนใจที่สุดคือสภาพการแข่งขันที่คล้ายกับการแข่งขันข้อมูลมาก แต่ก็ยังไม่เป็นเช่นนั้นเช่นในตัวอย่างง่ายๆนี้:
class Race {
static volatile int i;
static int uniqueInt() { return i++; }
}
เนื่องจากi
มีความผันผวนจึงไม่มีการแย่งชิงข้อมูล แต่จากมุมมองโปรแกรมถูกต้องมีสภาพการแข่งขันเนื่องจากการที่ไม่ใช่ atomicity ของทั้งสองดำเนินการ: อ่านi
, i+1
เขียน uniqueInt
หลายหัวข้ออาจได้รับค่าเดียวกันจาก
data race
ความหมายที่แท้จริงใน JLS ได้หรือไม่?
ไม่พวกเขาแตกต่างกันและทั้งสองไม่ได้เป็นส่วนย่อยของหนึ่งหรือในทางกลับกัน
คำว่าเงื่อนไขการแข่งขันมักจะสับสนกับการแข่งขันข้อมูลระยะที่เกี่ยวข้องซึ่งเกิดขึ้นเมื่อไม่ได้ใช้การซิงโครไนซ์เพื่อประสานการเข้าถึงทั้งหมดไปยังฟิลด์ที่ไม่ใช่ขั้นสุดท้ายที่ใช้ร่วมกัน คุณเสี่ยงต่อการแย่งชิงข้อมูลเมื่อใดก็ตามที่เธรดเขียนตัวแปรที่เธรดอื่นอาจอ่านถัดไปหรืออ่านตัวแปรที่เธรดอื่นอาจเขียนเป็นครั้งสุดท้ายหากเธรดทั้งสองไม่ใช้การซิงโครไนซ์ รหัสที่มีการแข่งขันข้อมูลไม่มีความหมายที่กำหนดไว้ที่เป็นประโยชน์ภายใต้ Java Memory Model เงื่อนไขการแข่งขันทั้งหมดไม่ใช่การแข่งขันข้อมูลและการแข่งขันข้อมูลทั้งหมดไม่ใช่เงื่อนไขการแข่งขัน แต่ทั้งสองอย่างอาจทำให้โปรแกรมที่ทำงานพร้อมกันล้มเหลวในรูปแบบที่คาดเดาไม่ได้
นำมาจากหนังสือยอดเยี่ยม - Java Concurrency in Practice โดย Joshua Bloch & Co.
TL; DR: ความแตกต่างระหว่างการแข่งขันของข้อมูลและสภาพการแข่งขันขึ้นอยู่กับลักษณะของการกำหนดปัญหาและตำแหน่งที่จะกำหนดขอบเขตระหว่างพฤติกรรมที่ไม่ได้กำหนดและพฤติกรรมที่กำหนดไว้อย่างชัดเจน แต่ไม่แน่นอน ความแตกต่างในปัจจุบันเป็นแบบธรรมดาและสะท้อนให้เห็นถึงส่วนติดต่อระหว่างสถาปนิกโปรเซสเซอร์และภาษาโปรแกรมได้ดีที่สุด
1. อรรถศาสตร์
การแข่งขันของข้อมูลหมายถึง "การเข้าถึงหน่วยความจำ" (หรือการกระทำหรือการดำเนินการ) ที่ขัดแย้งกันแบบไม่ซิงโครไนซ์กับตำแหน่งหน่วยความจำเดียวกัน หากไม่มีข้อขัดแย้งในการเข้าถึงหน่วยความจำในขณะที่ยังมีพฤติกรรมที่ไม่แน่นอนที่เกิดจากการสั่งการดำเนินการนั่นคือเงื่อนไขการแย่งชิง
หมายเหตุ "การเข้าถึงหน่วยความจำ" ที่นี่มีความหมายเฉพาะ โดยอ้างถึงการโหลดหน่วยความจำแบบ "บริสุทธิ์" หรือการดำเนินการจัดเก็บ ตัวอย่างเช่นที่เก็บหน่วยความจำจากเธรดหนึ่ง (จำเป็น) ไม่ทราบว่าต้องใช้เวลานานเท่าใดในการเขียนข้อมูลลงในหน่วยความจำและในที่สุดก็แพร่กระจายไปยังเธรดอื่น ตัวอย่างอื่นการจัดเก็บหน่วยความจำไปยังตำแหน่งหนึ่งก่อนที่จะจัดเก็บอีกแห่งไปยังตำแหน่งอื่นโดยเธรดเดียวกันไม่ได้ (จำเป็น) รับประกันว่าข้อมูลแรกที่เขียนในหน่วยความจำจะอยู่ก่อนที่สอง ด้วยเหตุนี้ลำดับของการเข้าถึงหน่วยความจำที่บริสุทธิ์เหล่านั้นจึงไม่ (จำเป็น) ที่จะสามารถ"ให้เหตุผล"ได้และจะมีอะไรเกิดขึ้นได้เว้นแต่จะกำหนดไว้เป็นอย่างดี
เมื่อ "การเข้าถึงหน่วยความจำ" ได้รับการกำหนดไว้อย่างดีในแง่ของการสั่งซื้อผ่านการซิงโครไนซ์ความหมายเพิ่มเติมจะช่วยให้มั่นใจได้ว่าแม้ว่าระยะเวลาของการเข้าถึงหน่วยความจำจะไม่แน่นอน แต่ก็สามารถ"ให้เหตุผล"ผ่านการซิงโครไนซ์ได้ หมายเหตุแม้ว่าการจัดลำดับระหว่างการเข้าถึงหน่วยความจำสามารถให้เหตุผลได้ แต่ก็ไม่จำเป็นต้องกำหนดเงื่อนไขการแข่งขัน
2. ทำไมความแตกต่าง?
แต่ถ้าคำสั่งซื้อยังคงไม่แน่นอนในสภาพการแข่งขันทำไมต้องแยกความแตกต่างจากการแข่งขันข้อมูล เหตุผลอยู่ในทางปฏิบัติมากกว่าทางทฤษฎี เป็นเพราะความแตกต่างมีอยู่ในส่วนต่อประสานระหว่างภาษาโปรแกรมและสถาปัตยกรรมตัวประมวลผล
คำแนะนำในการโหลด / จัดเก็บหน่วยความจำในสถาปัตยกรรมสมัยใหม่มักใช้เป็นการเข้าถึงหน่วยความจำแบบ "บริสุทธิ์" เนื่องจากลักษณะของไปป์ไลน์ที่ไม่ได้รับคำสั่งการเก็งกำไรแคชหลายระดับการเชื่อมต่อโครงข่าย cpu-ram โดยเฉพาะแบบมัลติคอร์เป็นต้น มีหลายปัจจัยที่นำไปสู่การกำหนดเวลาและการสั่งซื้อที่ไม่แน่นอน ในการบังคับใช้คำสั่งสำหรับทุกคำสั่งหน่วยความจำจะต้องรับโทษอย่างมากโดยเฉพาะอย่างยิ่งในการออกแบบโปรเซสเซอร์ที่รองรับมัลติคอร์ ดังนั้นความหมายการสั่งซื้อจึงมีคำแนะนำเพิ่มเติมเช่นอุปสรรคต่างๆ (หรือรั้ว)
การแย่งชิงข้อมูลคือสถานการณ์ของการดำเนินการตามคำสั่งโปรเซสเซอร์โดยไม่มีรั้วเพิ่มเติมเพื่อช่วยให้เหตุผลในการจัดลำดับการเข้าถึงหน่วยความจำที่ขัดแย้งกัน ผลลัพธ์ที่ได้ไม่เพียง แต่ไม่แน่นอน แต่ยังอาจแปลกมากเช่นการเขียนสองรายการไปยังตำแหน่งคำเดียวกันโดยใช้เธรดที่ต่างกันอาจส่งผลให้แต่ละคำเขียนครึ่งหนึ่งของคำหรืออาจดำเนินการตามค่าที่แคชไว้ในเครื่องเท่านั้น - สิ่งเหล่านี้เป็นพฤติกรรมที่ไม่ได้กำหนดจากมุมมองของโปรแกรมเมอร์ แต่ (โดยปกติ) ถูกกำหนดไว้อย่างดีจากมุมมองของสถาปนิกโปรเซสเซอร์
โปรแกรมเมอร์ต้องมีวิธีให้เหตุผลในการเรียกใช้โค้ด การแย่งชิงข้อมูลเป็นสิ่งที่พวกเขาไม่สมเหตุสมผลดังนั้นจึงควรหลีกเลี่ยง (โดยปกติ) นั่นคือเหตุผลที่ข้อกำหนดของภาษาที่มีระดับต่ำเพียงพอมักจะกำหนดการแข่งขันของข้อมูลเป็นพฤติกรรมที่ไม่ได้กำหนดซึ่งแตกต่างจากพฤติกรรมของหน่วยความจำที่กำหนดไว้อย่างดีของเงื่อนไขการแข่งขัน
3. โมเดลหน่วยความจำภาษา
โปรเซสเซอร์ที่แตกต่างกันอาจมีพฤติกรรมการเข้าถึงหน่วยความจำที่แตกต่างกันกล่าวคือรุ่นหน่วยความจำโปรเซสเซอร์ เป็นเรื่องที่น่าอึดอัดสำหรับโปรแกรมเมอร์ที่จะศึกษารูปแบบหน่วยความจำของโปรเซสเซอร์สมัยใหม่ทุกตัวจากนั้นจึงพัฒนาโปรแกรมที่สามารถใช้ประโยชน์จากมันได้ เป็นที่พึงปรารถนาหากภาษาสามารถกำหนดรูปแบบหน่วยความจำเพื่อให้โปรแกรมของภาษานั้นทำงานตามที่คาดไว้เสมอตามที่โมเดลหน่วยความจำกำหนด นั่นคือเหตุผลที่ Java และ C ++ มีการกำหนดโมเดลหน่วยความจำ เป็นภาระของผู้พัฒนาคอมไพเลอร์ / รันไทม์เพื่อให้แน่ใจว่าโมเดลหน่วยความจำภาษาถูกบังคับใช้ในสถาปัตยกรรมโปรเซสเซอร์ที่แตกต่างกัน
ที่กล่าวว่าหากภาษาไม่ต้องการเปิดเผยพฤติกรรมระดับต่ำของโปรเซสเซอร์ (และยินดีที่จะสละประโยชน์ด้านประสิทธิภาพบางประการของสถาปัตยกรรมสมัยใหม่) พวกเขาสามารถเลือกกำหนดรูปแบบหน่วยความจำที่ซ่อนรายละเอียดของ "บริสุทธิ์" ได้อย่างสมบูรณ์ การเข้าถึงหน่วยความจำ แต่ใช้ความหมายการสั่งซื้อสำหรับการดำเนินการหน่วยความจำทั้งหมด จากนั้นผู้พัฒนาคอมไพลเลอร์ / รันไทม์อาจเลือกที่จะปฏิบัติต่อตัวแปรหน่วยความจำทุกตัวแปรแบบระเหยในสถาปัตยกรรมโปรเซสเซอร์ สำหรับภาษาเหล่านี้ (ที่รองรับหน่วยความจำแบบแบ่งใช้ข้ามเธรด) ไม่มีการแข่งขันของข้อมูล แต่อาจยังคงเป็นเงื่อนไขการแข่งขันแม้จะมีภาษาที่สอดคล้องกันอย่างสมบูรณ์
ในทางกลับกันรูปแบบหน่วยความจำโปรเซสเซอร์อาจเข้มงวดกว่า (หรือผ่อนคลายน้อยลงหรือในระดับที่สูงขึ้น) เช่นการใช้ความสอดคล้องตามลำดับเหมือนที่โปรเซสเซอร์ในยุคแรกทำ จากนั้นการดำเนินการหน่วยความจำทั้งหมดจะได้รับคำสั่งและไม่มีการแย่งชิงข้อมูลสำหรับภาษาใด ๆ ที่ทำงานในโปรเซสเซอร์
4. สรุป
กลับไปที่คำถามเดิม IMHO เป็นการดีที่จะกำหนดการแข่งขันของข้อมูลเป็นกรณีพิเศษของเงื่อนไขการแข่งขันและสภาพการแข่งขันในระดับหนึ่งอาจกลายเป็นการแย่งข้อมูลในระดับที่สูงขึ้น ขึ้นอยู่กับลักษณะของการกำหนดปัญหาและตำแหน่งที่จะวาดขอบเขตระหว่างพฤติกรรมที่ไม่ได้กำหนดกับพฤติกรรมที่กำหนดไว้อย่างดี แต่ไม่แน่นอน เพียงอนุสัญญาปัจจุบันกำหนดขอบเขตที่อินเตอร์เฟสตัวประมวลผลภาษาไม่จำเป็นต้องหมายความว่าจะเป็นเช่นนั้นเสมอไปและจะต้องเป็นเช่นนั้นเสมอไป แต่แบบแผนปัจจุบันอาจสะท้อนให้เห็นถึงอินเทอร์เฟซที่ล้ำสมัย (และภูมิปัญญา) ระหว่างสถาปนิกโปรเซสเซอร์และภาษาโปรแกรมได้ดีที่สุด