สิ่งที่ป้องกันไม่ให้สภาพการแข่งขันในการล็อค?


24

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

จะเกิดอะไรขึ้น? จะทำอย่างไรเพื่อป้องกันสิ่งนั้น มันเป็นไปไม่ได้หรือไม่น่าเป็นไปได้? หรือว่าเป็นสภาพการแข่งขันที่แท้จริงที่จะเกิดขึ้น?


คำถามนี้ถูกถามมาก่อนใน SO: stackoverflow.com/questions/980521/…
Doc Brown

และคำถามที่เกี่ยวข้องที่นี่ใน P.SE: programmers.stackexchange.com/questions/228827/…
ratchet freak

คุณได้รับล็อคเพื่อรับล็อค;) (ในคำอื่น ๆ ถ้าล็อคของคุณมีสภาพการแข่งขันมันไม่ได้ดำเนินการอย่างถูกต้อง - ล็อคถูกกำหนดสวยมากที่จะสร้างที่ดำเนินการยกเว้นซึ่งกันและกัน)
Tangrs

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

คำตอบ:


36

มันเป็นไปไม่ได้หรือไม่น่าเป็นไปได้?

เป็นไปไม่ได้ มันสามารถนำไปใช้ในรูปแบบที่แตกต่างกันเช่นผ่านการเปรียบเทียบและแลกเปลี่ยนที่ฮาร์ดแวร์รับประกันการดำเนินการตามลำดับ มันอาจมีความซับซ้อนเล็กน้อยเมื่อมีหลายแกนหรือหลายซ็อกเก็ตและต้องการโปรโตคอลที่ซับซ้อนระหว่างแกน แต่สิ่งนี้ได้รับการดูแล


3
ขอบคุณ ... พระเจ้า ... จัดการกับฮาร์ดแวร์ ... (หรืออย่างน้อยก็ต่ำกว่าระดับที่เราสัมผัส)
corsiKa

2
@ gdhoward ฉันไม่อยากจะเชื่อเลย ... คำตอบนี้ใช้เวลาน้อยกว่า 5 นาทีและนี่เป็นครั้งที่สามที่ได้รับการโหวตสูงสุดจากสี่ร้อยคำตอบของฉัน (ส่วนใหญ่แล้ว) และก็น่าจะสั้นที่สุด
maaartinus

1
@maaartinus - บางครั้งสั้นและหวาน
Bobson

17

ศึกษาแนวคิดของการดำเนินการ "ทดสอบและตั้งค่า" ของอะตอม

โดยพื้นฐานแล้วการดำเนินการไม่สามารถแบ่งได้ - เป็นไปไม่ได้ที่สองสิ่งจะทำในเวลาเดียวกัน มันจะตรวจสอบค่าตั้งถ้ามันชัดเจนและคืนค่าเหมือนเมื่อทดสอบ ในการดำเนินการล็อคผลลัพธ์จะเป็น "lock == TRUE" เสมอหลังจากการทดสอบและตั้งค่าความแตกต่างเพียงอย่างเดียวคือมันถูกตั้งค่าหรือไม่เมื่อเริ่มต้น

ที่ระดับรหัสไมโครในหน่วยประมวลผลแกนเดียวนี่คือคำสั่งที่แบ่งแยกไม่ได้และใช้งานง่าย ด้วยโปรเซสเซอร์หลายตัวและมัลติคอร์มันจะกลายเป็นเรื่องยากขึ้น แต่ในฐานะโปรแกรมเมอร์เราไม่จำเป็นต้องกังวลเกี่ยวกับมันเพราะมันถูกออกแบบมาเพื่อทำงานโดยคนฉลาดจริงๆที่ทำซิลิคอน โดยพื้นฐานแล้วพวกเขาทำสิ่งเดียวกัน - สร้างคำสั่งอะตอมมิชชันซึ่งเป็นเวอร์ชั่นทดสอบและเซ็ตแฟนซี


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

@BillMichell ฉันควรจะคิดอย่างนั้น ที่จริงฉันทำ ฉันไม่รู้ว่าสมมติฐานของฉันถูกต้องหรือไม่
กาวิน Howard

2

เพียงแค่ใส่รหัสเพื่อเข้าสู่ส่วนที่สำคัญได้รับการออกแบบเป็นพิเศษเพื่อให้สภาพการแข่งขันไม่ได้เป็นการละเมิดการยกเว้นซึ่งกันและกัน

เวลาส่วนใหญ่ของอะตอมเปรียบเทียบและตั้งค่าลูปจะใช้ที่ดำเนินการในระดับฮาร์ดแวร์

while(!CompareAndSet(&lock, false, true));//busy loop won't continue until THIS thread has set the lock to true
//critical section
CompareAndSet(&lock, true, false);

ในกรณีที่ไม่มีโซลูชันซอฟต์แวร์ที่ศึกษาอย่างดีเพื่อให้สามารถยกเว้นซึ่งกันและกัน


1

เป็นไปไม่ได้ที่เธรดสองตัว (หรือมากกว่า) จะได้รับการล็อคในเวลาเดียวกัน มีวิธีการซิงโครไนซ์ไม่กี่ชนิดเช่น:

การรอคอยที่ใช้งาน - ล็อคการหมุน

pseudocode:

1. while ( xchg(lock, 1) == 1); - entry protocole

XCHG เป็นตัวอย่างของการทำงานแบบปรมาณู (มีอยู่ในสถาปัตยกรรม x86) ซึ่งตั้งค่าใหม่เป็นครั้งแรกสำหรับตัวแปร "ล็อค" แล้วส่งคืนค่าเดิม อะตอมมิกหมายความว่ามันไม่สามารถขัดจังหวะ - ในตัวอย่างข้างต้นระหว่างการตั้งค่าใหม่และเก่าคืน อะตอม - ผลลัพธ์ที่กำหนดขึ้นไม่ว่าอะไรจะเกิดขึ้น

2. Your code
3. lock = 0; - exit protocol

เมื่อล็อกเท่ากับ 0 เธรดอื่นสามารถเข้าสู่ส่วนที่สำคัญ - ในขณะที่ลูปสิ้นสุด

การระงับเธรด - ตัวอย่างเช่นการนับเซมาฟอร์นับ

มีสองการดำเนินงานของอะตอมที่มีอยู่.Wait()และและเรามีจำนวนเต็มตัวแปรช่วยให้เรียกว่า.Signal()int currentValue

Wait():
if (currentValue > 0) currentValue -= 1;
else suspend current thread;

Signal():
If there exists thread suspended by semaphore wake up one of them
Else currentValue += 1;

ตอนนี้การแก้ปัญหาส่วนที่สำคัญเป็นเรื่องง่าย:

pseudocode:

mySemaphore.Wait();
do some operations - critical section
mySemaphore.Signal();

โดยปกติ API เธรดการเขียนโปรแกรมของคุณควรให้ความสามารถในการระบุเธรดที่เกิดขึ้นพร้อมกันสูงสุดในเซกเมนต์วิกฤติส่วน เห็นได้ชัดว่ามีการซิงโครไนซ์ประเภทอื่น ๆ ในระบบหลายเธรด (mutex, จอภาพ, สัญญาณเซมาฟอร์และอื่น ๆ ) แต่ก็มีพื้นฐานอยู่เหนือแนวคิด เราอาจโต้แย้งได้ว่าวิธีการที่ใช้เธรดที่หยุดทำงานชั่วคราวนั้นน่าจะดีกว่าการรอคอย (ดังนั้น cpu จะไม่สูญเปล่า) - มันไม่ได้เป็นความจริงเสมอไป เมื่อเธรดถูกระงับ - การดำเนินการที่แพงเรียกว่า context switch เกิดขึ้น อย่างไรก็ตามมีเหตุผลเมื่อรอเวลาสั้น (จำนวนเธรด ~ จำนวนแกน)

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