ล็อค, mutex, สัญญาณ…อะไรคือความแตกต่าง?


439

ฉันได้ยินคำเหล่านี้เกี่ยวข้องกับการเขียนโปรแกรมพร้อมกัน แต่ความแตกต่างระหว่างพวกเขาคืออะไร



2
คำอธิบายที่ดีที่สุดที่ฉันเคยเห็น: crystal.uta.edu/~ylei/cse6324/data/semaphore.pdf
expoter

1
มีความเป็นไปได้ที่จะเกิดความแตกต่างระหว่างเซมาฟอร์ไบนารีและ mutex

คำตอบ:


534

ล็อคอนุญาตให้เธรดเดียวเท่านั้นที่จะเข้าสู่ส่วนที่ถูกล็อคและล็อคไม่ได้ถูกแชร์กับกระบวนการอื่น ๆ

mutex เหมือนกับล็อค แต่สามารถเป็นระบบได้กว้าง (ใช้ร่วมกันโดยหลายกระบวนการ)

เซมาฟอร์ทำเช่นเดียวกันกับ mutex แต่อนุญาตให้มีจำนวนเธรด x ให้ป้อนซึ่งสามารถใช้ยกตัวอย่างเช่นเพื่อ จำกัด จำนวนของ cpu, io หรือ ram ที่ทำงานหนักในเวลาเดียวกัน

สำหรับการโพสต์รายละเอียดเพิ่มเติมเกี่ยวกับความแตกต่างระหว่าง mutex และสัญญาณอ่านที่นี่

นอกจากนี้คุณยังมีล็อคการอ่าน / เขียนที่อนุญาตให้มีจำนวนผู้อ่านไม่ จำกัด หรือนักเขียน 1 คนในเวลาใดก็ได้


2
@mertinan ฉันไม่สามารถพูดได้ว่าผมเคยได้ยินเกี่ยวกับมัน แต่นี่คือสิ่งที่วิกิพีเดียบอกว่า "กลอน (ฐานข้อมูล), (ที่ค่อนข้างสั้น ๆ ) ล็อคในระบบข้อมูลโครงสร้างเช่นดัชนี"
ปีเตอร์

2
จอภาพอนุญาตให้รอเงื่อนไขบางอย่าง (เช่นเมื่อปล่อยล็อค), "จอภาพ"
Dzmitry Lazerka

25
สัญญาณไม่เหมือนกับ mutex พวกเขาจะใช้แตกต่างกันมากและยังมีคุณสมบัติที่แตกต่างกัน ดูตัวอย่างbarrgroup.com/Embedded-Systems/How-To/RTOS-Mutex-Semaphoreสำหรับรายละเอียด
nanoquack

3
@nanoquack รู้สึกอิสระที่จะแก้ไขคำตอบของฉันถ้าคุณรู้สึกว่ามันทำให้เข้าใจผิดหรือไม่ถูกต้อง
ปีเตอร์

3
สำหรับความแตกต่างที่ชัดเจนระหว่าง mutex และสัญญาณในลิงค์ของ nanoquack วรรคสำคัญคือ " การใช้สัญญาณที่ถูกต้องคือการส่งสัญญาณจากงานหนึ่งไปยังอีกงานหนึ่ง mutex จะถูกนำมาใช้และเผยแพร่ตามลำดับโดยแต่ละครั้ง งานที่ใช้ทรัพยากรที่ใช้ร่วมกันซึ่งจะป้องกันในทางกลับกันงานที่ใช้ semaphores ส่งสัญญาณหรือรอ - ไม่ใช่ทั้งคู่ "
ToolmakerSteve

117

มีความเข้าใจผิดมากมายเกี่ยวกับคำเหล่านี้

นี่คือจากโพสต์ก่อนหน้า ( https://stackoverflow.com/a/24582076/3163691 ) ซึ่งเหมาะที่สุดที่นี่:

1) ส่วนที่สำคัญ = วัตถุผู้ใช้ที่ใช้ในการอนุญาตการดำเนินการของเธรดที่ใช้งานเพียงหนึ่งเดียวจากหลาย ๆ รายการภายในกระบวนการเดียว ไม่ใช่เลือกหัวข้ออื่น ๆ (@ แสวงหาวัตถุนี้) จะนำไปนอนหลับ

[ไม่มีความสามารถในการประมวลผลวัตถุดั้งเดิมมาก]

2) Mutex สัญญาณ (aka Mutex) = วัตถุเคอร์เนลที่ใช้สำหรับช่วยให้การดำเนินการของเพียงด้ายที่ใช้งานอย่างใดอย่างหนึ่งจากคนอื่น ๆ อีกมากมายในหมู่กระบวนการที่แตกต่าง ไม่ใช่เลือกหัวข้ออื่น ๆ (@ แสวงหาวัตถุนี้) จะนำไปนอนหลับ วัตถุนี้รองรับการเป็นเจ้าของเธรดการแจ้งเตือนการยกเลิกเธรดการเรียกซ้ำ (การเรียก 'รับ' หลายครั้งจากเธรดเดียวกัน) และ 'การหลีกเลี่ยงลำดับความสำคัญของการย้อนกลับ'

[ความสามารถในการประมวลผลปลอดภัยมากในการใช้วัตถุการซิงโครไนซ์ 'ระดับสูง']

3) การนับเซมาฟอร์ (หรือที่เรียกว่าเซมาฟอร์) = วัตถุเคอร์เนลที่ใช้ในการอนุญาตการทำงานของกลุ่มของเธรดที่ใช้งานอยู่จากหลาย ๆ ไม่ใช่เลือกหัวข้ออื่น ๆ (@ แสวงหาวัตถุนี้) จะนำไปนอนหลับ

[ความสามารถในการประมวลผลไม่ปลอดภัยมากที่จะใช้เพราะมันขาดคุณสมบัติ 'mutex': การแจ้งเตือนการยกเลิกเธรด, การเรียกซ้ำ?, 'การหลีกเลี่ยงการกลับลำดับความสำคัญ'? ฯลฯ ]

4) และตอนนี้พูดถึง 'spinlocks' ก่อนอื่นคำจำกัดความ:

Critical Region = ขอบเขตของหน่วยความจำที่ใช้ร่วมกันโดย 2 กระบวนการขึ้นไป

Lock = ตัวแปรที่ค่าอนุญาตหรือปฏิเสธการเข้าสู่ 'พื้นที่สำคัญ' (สามารถนำไปใช้เป็น 'ธงบูลีน' ได้ง่าย)

Busy wait = การทดสอบตัวแปรอย่างต่อเนื่องจนกว่าค่าบางค่าจะปรากฏขึ้น

สุดท้าย:

spinlock (aka spinlock) = a ล็อคที่ใช้รอไม่ว่าง (การรับล็อคทำโดยxchgหรือการดำเนินการปรมาณูที่คล้ายกัน)

[ไม่มีการนอนหลับของเธรดส่วนใหญ่จะใช้ในระดับเคอร์เนลเท่านั้น ไม่มีประสิทธิภาพสำหรับรหัสระดับผู้ใช้]

เป็นความคิดเห็นสุดท้ายฉันไม่แน่ใจ แต่ฉันสามารถเดิมพันคุณ bucks ใหญ่บางอย่างที่ 3 วัตถุแรกที่ซิงโครไนซ์ข้างต้น (# 1, # 2 และ # 3) ใช้ประโยชน์จากสัตว์ร้ายง่าย ๆ นี้ (# 4) เป็นส่วนหนึ่งของการใช้งาน

ขอให้เป็นวันที่ดี!

อ้างอิง:

แนวคิดเรียลไทม์สำหรับระบบสมองกลฝังตัวโดย Qing Li กับ Caroline Yao (CMP Books)

- ระบบปฏิบัติการสมัยใหม่ (ที่ 3) โดย Andrew Tanenbaum (Pearson Education International)

- โปรแกรมแอปพลิเคชันสำหรับ Microsoft Windows (รุ่นที่ 4) โดย Jeffrey Richter (Microsoft Programming Series)

นอกจากนี้คุณสามารถดูได้ที่: https://stackoverflow.com/a/24586803/3163691


1
ส่วนที่สำคัญจริง ๆ แล้วไม่ใช่วัตถุเคอร์เนลจึงมีน้ำหนักเบาและไม่สามารถซิงโครไนซ์ข้ามกระบวนการได้มากขึ้น
Vladislavs Burakovs

2
@ Vladislavs Burakovs: คุณพูดถูก! ยกโทษให้ฉัน ฉันจะแก้ไขเพื่อประโยชน์ในการเชื่อมโยงกัน
fante

สำหรับความแตกต่างที่ชัดเจนระหว่าง mutex และเซมาฟอร์ขณะที่ nanoquack กล่าวถึงที่อื่นให้ดูที่barrgroup.com/Embedded-Systems/How-To/RTOS-Mutex-Semaphore - ย่อหน้าที่สำคัญคือ " การใช้เซมาฟอร์ที่ถูกต้องใช้สำหรับการส่งสัญญาณจากงานหนึ่งงาน ไปยังอีก mutex หมายถึงการใช้และปล่อยออกมาตามลำดับโดยแต่ละงานที่ใช้ทรัพยากรที่ใช้ร่วมกันซึ่งจะปกป้องในทางตรงกันข้ามงานที่ใช้เซมาฟอร์ส่งสัญญาณหรือรอ - ไม่ใช่ทั้งคู่ "
ToolmakerSteve

คาดเดากลไกการล็อคอื่น ๆ ที่สร้างบน spinlock [ไม่มีประสิทธิภาพ]: ไม่น่าเป็นไปได้; AFAIK ต้องการการดำเนินการแบบปรมาณูเพียงบางส่วนเท่านั้นและคิวการพัก แม้ในที่ที่ spinlock เป็นจำเป็นภายในเคอร์เนลโซลูชั่นที่ทันสมัยลดผลกระทบตามที่กล่าวไว้ในวิกิพีเดีย - Spinlock - ทางเลือก - " .. ใช้วิธีไฮบริดที่เรียกว่า 'การปรับตัว mutex' ความคิดคือการใช้ spinlock เมื่อพยายามที่จะเข้าถึงทรัพยากรล็อคโดย. เธรดที่กำลังทำงานอยู่ แต่จะหยุดทำงานหากเธรดไม่ได้ทำงานอยู่ในขณะนี้ (อันหลังเป็นกรณีของระบบตัวประมวลผลเดียวเสมอ) "
ToolmakerSteve

@ToolmakerSteve ฉันกล้าที่จะให้ 'แก้ปัญหา' โดยไม่ต้อง 'spinlock' สำหรับปัญหาของ 'การชน' ที่พยายาม 'แทรก' ID เธรดเป็น 'คิวคิว' อย่างไรก็ตามข้อความ Wikipedia สรุปว่ามีการใช้ spinlock ในการใช้งาน !!!
fante

27

ปัญหาส่วนใหญ่สามารถแก้ไขได้โดยใช้ (i) เพียงล็อค (ii) เพียงแค่เซมาฟอร์, ... หรือ (iii) ทั้งสองอย่างรวมกัน! ในขณะที่คุณอาจได้ค้นพบที่พวกเขากำลังที่คล้ายกันมากทั้งป้องกันไม่ให้สภาพการแข่งขันทั้งสองมีacquire()/ release()การดำเนินงานทั้งสาเหตุศูนย์หรือมากกว่าที่จะกลายเป็นหัวข้อที่ถูกบล็อก / สงสัยว่า ... จริงๆเป็นสิ่งสำคัญแตกต่างอยู่เพียงผู้เดียวในวิธีการที่พวกเขาล็อคและปลดล็อค

  • การล็อก (หรือmutex ) มีสองสถานะ (0 หรือ 1) มันสามารถเป็นได้ทั้งปลดล็อคหรือล็อค พวกเขามักจะใช้เพื่อให้แน่ใจว่าเพียงหนึ่งด้ายเข้าสู่ส่วนที่สำคัญในเวลา
  • สัญญาณมีหลายรัฐ (0, 1, 2, ... ) สามารถล็อคได้ (สถานะ 0) หรือปลดล็อค (สถานะ 1, 2, 3, ... ) หนึ่งเซมาฟอร์มักใช้ร่วมกันเพื่อให้แน่ใจว่ามีเธรดเดียวเท่านั้นที่เข้าสู่ส่วนที่สำคัญได้อย่างแม่นยำเมื่อจำนวนหน่วยของทรัพยากรบางส่วนมี / ยังไม่ถึงค่าเฉพาะ (เช่นผ่านการนับลงไปที่ค่านั้นหรือนับถึงค่านั้น )

สำหรับการล็อก / เซมาฟอร์ทั้งสองพยายามโทรacquire()ในขณะที่ดั้งเดิมอยู่ในสถานะ 0 ทำให้เธรดการเรียกใช้ถูกหยุดชั่วคราว สำหรับล็อค - ความพยายามในการรับล็อคอยู่ในสถานะ 1 สำเร็จ สำหรับเซมาฟอร์ - ความพยายามในการรับการล็อกในสถานะ {1, 2, 3, ... } สำเร็จ

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

จากการสนทนาก่อนหน้านี้เราจะเห็นว่าล็อคมีความคิดของเจ้าของ (เธรดเพียงอย่างเดียวที่สามารถเรียกการเปิดตัวเป็นเจ้าของ) ในขณะที่เซมาฟอร์ไม่มีเจ้าของ (เธรดใด ๆ สามารถเรียกปล่อยบนสัญญาณ)


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

รูปแบบที่สำคัญที่ควรพิจารณา :

  • สิ่งที่ควรเรียกacquire()/ release()ถูก? - [แตกต่างกันไปอย่างมาก ]
  • ล็อค / สัญญาณของคุณใช้ "คิว" หรือ "ตั้ง" เพื่อจำกระทู้รอ?
  • ล็อค / เซมาฟอร์ของคุณสามารถแชร์กับเธรดของกระบวนการอื่นได้หรือไม่?
  • ล็อคของคุณเป็น "reentrant" หรือไม่ - [โดยปกติใช่]
  • ล็อคของคุณเป็น "บล็อก / ไม่บล็อก" หรือไม่? - [โดยปกติการไม่ปิดกั้นจะใช้เป็นการปิดกั้นการล็อค
  • คุณจะมั่นใจได้อย่างไรว่าการดำเนินการเป็น "อะตอม"?

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


C, C ++ ( pthreads )

  • mutexpthread_mutex_tจะดำเนินการผ่านทาง โดยค่าเริ่มต้นที่พวกเขาไม่สามารถใช้ร่วมกับกระบวนการอื่น ๆ ( PTHREAD_PROCESS_PRIVATE) แต่ของ mutex มีคุณลักษณะที่เรียกว่าpshared เมื่อตั้งค่าดังนั้น mutex จะถูกใช้ร่วมกันระหว่างกระบวนการ ( PTHREAD_PROCESS_SHARED)
  • การล็อคนั้นเหมือนกับ mutex
  • สัญญาณsem_tจะดำเนินการผ่านทาง คล้ายกับ mutexes semaphores สามารถใช้ร่วมกันระหว่าง threasds ของกระบวนการจำนวนมากหรือเก็บไว้เป็นส่วนตัวกับเธรดของกระบวนการเดียว นี้ขึ้นอยู่กับpsharedsem_initอาร์กิวเมนต์ให้กับ

หลาม ( threading.py )

  • ล็อค ( threading.RLock) เป็นส่วนใหญ่เช่นเดียวกับ C / C ++ pthread_mutex_ts ทั้งสองมีทั้งreentrant ซึ่งหมายความว่าพวกเขาอาจถูกปลดล็อกโดยเธรดเดียวกับที่ล็อกไว้ มันเป็นกรณีที่sem_tsemaphores, threading.Semaphoresemaphores และtheading.Lockล็อคไม่ได้ reentrant - เป็นกรณีที่ด้ายใด ๆ ที่สามารถดำเนินการปลดล็อคล็อค / ลงสัญญาณ
  • mutexเป็นเช่นเดียวกับล็อค (คำที่ไม่ได้ใช้บ่อยในหลาม)
  • สัญญาณ ( threading.Semaphore) sem_tเป็นส่วนใหญ่เช่นเดียวกับ แม้ว่าจะมีsem_tคิวรหัสเธรดที่ใช้ในการจำลำดับที่กระทู้ถูกบล็อคเมื่อพยายามล็อคมันในขณะที่มันถูกล็อค เมื่อเธรดปลดล็อกเซมาฟอร์เธรดแรกในคิว (ถ้ามี) จะถูกเลือกให้เป็นเจ้าของใหม่ ตัวระบุเธรดถูกนำออกจากคิวและสัญญาณจะถูกล็อคอีกครั้ง อย่างไรก็ตามด้วยthreading.Semaphoreชุดจะใช้แทนคิวดังนั้นลำดับที่เธรดกลายเป็นบล็อกจะไม่ถูกเก็บไว้ - เธรดใด ๆในชุดอาจถูกเลือกให้เป็นเจ้าของรายต่อไป

Java ( java.util.concurrent )

  • ล็อค ( java.util.concurrent.ReentrantLock) เป็นส่วนใหญ่เช่นเดียวกับ C / C ++ pthread_mutex_t's และงูใหญ่threading.RLockในการที่จะยังดำเนินการล็อค reentrant การแชร์การล็อกระหว่างกระบวนการนั้นยากขึ้นใน Java เนื่องจาก JVM ทำหน้าที่เป็นตัวกลาง ถ้าด้ายพยายามที่จะปลดล็อคล็อคมันไม่ได้เองการIllegalMonitorStateExceptionโยน
  • mutexเป็นเช่นเดียวกับล็อค (คำที่ไม่ได้ใช้บ่อยใน Java)
  • สัญญาณ ( java.util.concurrent.Semaphore) เป็นส่วนใหญ่เช่นเดียวกับและsem_t threading.Semaphoreตัวสร้างสำหรับเซมาฟอร์ Java ยอมรับพารามิเตอร์บูลีนความเป็นธรรมที่ควบคุมว่าจะใช้ชุด (เท็จ) หรือคิว (จริง) สำหรับการจัดเก็บเธรดที่รออยู่

ในทางทฤษฎี semaphores มักถูกกล่าวถึง แต่ในทางปฏิบัติ semaphores ไม่ได้ใช้มากนัก สัญญาณส่งสัญญาณจะเก็บสถานะของจำนวนเต็มหนึ่งเดียวเท่านั้นดังนั้นบ่อยครั้งที่สัญญาณค่อนข้างยืดหยุ่นและจำเป็นต้องใช้หลายครั้งพร้อมกันทำให้เกิดความยากลำบากในการทำความเข้าใจรหัส นอกจากนี้ความจริงที่ว่าเธรดใด ๆสามารถปล่อยสัญญาณได้บางครั้งก็เป็นสิ่งที่ไม่พึงประสงค์ ดั้งเดิม / การซิงโครไนซ์เชิงวัตถุในระดับที่สูงขึ้นเช่น "ตัวแปรเงื่อนไข" และ "มอนิเตอร์" จะถูกนำมาใช้แทน


22

ดูMultithreading Tutorialของ John Kopplin

ในส่วนการซิงโครไนซ์ระหว่างเธรดเขาอธิบายความแตกต่างระหว่างเหตุการณ์ล็อก mutex เซมาฟอร์ตัวจับเวลาที่รอได้

mutexสามารถเป็นเจ้าของโดยเพียงหนึ่งหัวข้อที่เวลาการเปิดใช้หัวข้อในการประสานงานการเข้าถึงพิเศษร่วมกันกับทรัพยากรที่ใช้ร่วมกัน

วัตถุส่วนที่สำคัญให้การซิงโครไนซ์ที่คล้ายกับที่ให้ไว้โดยวัตถุ mutex ยกเว้นว่าวัตถุส่วนที่สำคัญสามารถใช้โดยเธรดของกระบวนการเดียวเท่านั้น

ความแตกต่างอื่นระหว่างmutexและส่วนวิกฤติคือถ้าวัตถุส่วนสำคัญเป็นเจ้าของโดยเธรดอื่นให้ EnterCriticalSection()รอกรรมสิทธิ์โดยไม่มีกำหนดในขณะ WaitForSingleObject()ที่ใช้กับ mutex ช่วยให้คุณสามารถระบุการหมดเวลา

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


15

ฉันจะพยายามคลุมด้วยตัวอย่าง:

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

private static readonly Object obj = new Object();

lock (obj) //after object is locked no thread can come in and insert item into dictionary on a different thread right before other thread passed the check...
{
    if (!sharedDict.ContainsKey(key))
    {
        sharedDict.Add(item);
    }
}

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

ตัวอย่างรหัสที่ฉันรักเป็นหนึ่งในคนโกหกที่ได้รับจาก @Patric - นี่มันไป:

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace TheNightclub
{
    public class Program
    {
        public static Semaphore Bouncer { get; set; }

        public static void Main(string[] args)
        {
            // Create the semaphore with 3 slots, where 3 are available.
            Bouncer = new Semaphore(3, 3);

            // Open the nightclub.
            OpenNightclub();
        }

        public static void OpenNightclub()
        {
            for (int i = 1; i <= 50; i++)
            {
                // Let each guest enter on an own thread.
                Thread thread = new Thread(new ParameterizedThreadStart(Guest));
                thread.Start(i);
            }
        }

        public static void Guest(object args)
        {
            // Wait to enter the nightclub (a semaphore to be released).
            Console.WriteLine("Guest {0} is waiting to entering nightclub.", args);
            Bouncer.WaitOne();          

            // Do some dancing.
            Console.WriteLine("Guest {0} is doing some dancing.", args);
            Thread.Sleep(500);

            // Let one guest out (release one semaphore).
            Console.WriteLine("Guest {0} is leaving the nightclub.", args);
            Bouncer.Release(1);
        }
    }
}

Mutexมันค่อนข้างSemaphore(1,1)บ่อยและใช้กันทั่วโลก (แอพพลิเคชั่นที่กว้างlockกว่านั้นมีความเหมาะสมมากกว่า) หนึ่งจะใช้ทั่วโลกMutexเมื่อลบโหนดจากรายการที่สามารถเข้าถึงได้ทั่วโลก (สิ่งสุดท้ายที่คุณต้องการหัวข้ออื่นที่จะทำบางสิ่งบางอย่างในขณะที่คุณกำลังลบโหนด) เมื่อคุณได้รับMutexหากเธรดที่แตกต่างพยายามที่จะได้รับเหมือนกันMutexมันจะถูกนำไปสู่โหมดสลีปจนถึงเธรด SAME ที่ได้รับการMutexเผยแพร่

ตัวอย่างที่ดีในการสร้าง global mutex คือ @deepee

class SingleGlobalInstance : IDisposable
{
    public bool hasHandle = false;
    Mutex mutex;

    private void InitMutex()
    {
        string appGuid = ((GuidAttribute)Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(GuidAttribute), false).GetValue(0)).Value.ToString();
        string mutexId = string.Format("Global\\{{{0}}}", appGuid);
        mutex = new Mutex(false, mutexId);

        var allowEveryoneRule = new MutexAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), MutexRights.FullControl, AccessControlType.Allow);
        var securitySettings = new MutexSecurity();
        securitySettings.AddAccessRule(allowEveryoneRule);
        mutex.SetAccessControl(securitySettings);
    }

    public SingleGlobalInstance(int timeOut)
    {
        InitMutex();
        try
        {
            if(timeOut < 0)
                hasHandle = mutex.WaitOne(Timeout.Infinite, false);
            else
                hasHandle = mutex.WaitOne(timeOut, false);

            if (hasHandle == false)
                throw new TimeoutException("Timeout waiting for exclusive access on SingleInstance");
        }
        catch (AbandonedMutexException)
        {
            hasHandle = true;
        }
    }


    public void Dispose()
    {
        if (mutex != null)
        {
            if (hasHandle)
                mutex.ReleaseMutex();
            mutex.Dispose();
        }
    }
}

จากนั้นใช้ like:

using (new SingleGlobalInstance(1000)) //1000ms timeout on global lock
{
    //Only 1 of these runs at a time
    GlobalNodeList.Remove(node)
}

หวังว่านี่จะช่วยคุณประหยัดเวลา


8

Wikipedia มีหัวข้อที่ยอดเยี่ยมเกี่ยวกับความแตกต่างระหว่าง Semaphores และ Mutexes :

Mutex นั้นโดยพื้นฐานแล้วเป็นสิ่งเดียวกับสัญญาณแบบไบนารีและบางครั้งใช้การใช้งานพื้นฐานแบบเดียวกัน ความแตกต่างระหว่างพวกเขาคือ:

Mutexes มีแนวคิดของเจ้าของซึ่งเป็นกระบวนการที่ล็อค mutex เฉพาะกระบวนการที่ล็อก mutex เท่านั้นที่สามารถปลดล็อกได้ ในทางตรงกันข้ามสัญญาณไม่มีแนวคิดของเจ้าของ กระบวนการใด ๆ สามารถปลดล็อคสัญญาณ

ซึ่งแตกต่างจาก semaphores, mutexes ให้ความปลอดภัยการกลับลำดับความสำคัญ เนื่องจาก mutex รู้จักเจ้าของปัจจุบันจึงเป็นไปได้ที่จะโปรโมตลำดับความสำคัญของเจ้าของเมื่อใดก็ตามที่งานที่มีลำดับความสำคัญสูงกว่าเริ่มรอ mutex

Mutexes ยังให้ความปลอดภัยในการลบซึ่งกระบวนการที่ถือ mutex นั้นไม่สามารถลบได้โดยไม่ตั้งใจ Semaphores ไม่ได้ให้สิ่งนี้


5

ความเข้าใจของฉันคือว่า mutex ใช้สำหรับกระบวนการเดียวเท่านั้น แต่ข้ามหลายเธรดในขณะที่เซมาฟอร์อาจใช้ข้ามหลายกระบวนการและข้ามชุดเธรดที่เกี่ยวข้อง

นอกจากนี้ mutex เป็นเลขฐานสอง (มันถูกล็อคหรือปลดล็อค) ในขณะที่สัญญาณมีความคิดในการนับหรือคิวมากกว่าหนึ่งคำขอล็อคและปลดล็อค

มีคนช่วยยืนยันคำอธิบายของฉันได้ไหม ฉันพูดในบริบทของ Linux โดยเฉพาะ Red Hat Enterprise Linux (RHEL) เวอร์ชัน 6 ซึ่งใช้เคอร์เนล 2.6.32


3
ตอนนี้อาจจะแตกต่างกันในระบบปฏิบัติการที่แตกต่างกัน แต่ในหน้าต่าง Mutex สามารถใช้กระบวนการหลายอย่างน้อยวัตถุ .net Mutex ..
ปีเตอร์

2
stackoverflow.com/questions/9389730/… "เธรดภายในกระบวนการเดียวกันหรือภายในกระบวนการอื่นสามารถแชร์ mutexes ได้" ดังนั้นไม่มี mutex ต้องไม่เฉพาะกระบวนการ
ปีเตอร์

3

ใช้การเขียนโปรแกรม C บนตัวแปร Linux เป็นกรณีพื้นฐานสำหรับตัวอย่าง

ล็อค:

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

•ไม่มีแนวคิดเรื่องการเป็นเจ้าของเธรดลำดับความสำคัญการเรียงลำดับ ฯลฯ

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

•โดยปกติจะขึ้นอยู่กับการดำเนินการของอะตอมเช่นการทดสอบและการตั้งค่าการเปรียบเทียบและสลับการดึงข้อมูลและเพิ่มเป็นต้น

•โดยทั่วไปต้องการการสนับสนุนฮาร์ดแวร์สำหรับการทำงานของอะตอม

ล็อคไฟล์:

•มักใช้เพื่อประสานงานการเข้าถึงไฟล์ผ่านหลายกระบวนการ

•หลายโพรเซสสามารถเก็บล็อกการอ่านได้อย่างไรก็ตามเมื่อโพรเซสเดี่ยวใด ๆ เก็บล็อกการเขียนไม่อนุญาตให้โพรเซสอื่นทำการรับล็อกการอ่านหรือการเขียน

•ตัวอย่าง: ฝูง fcntl ฯลฯ

mutex:

•การเรียกใช้ฟังก์ชัน Mutex มักจะทำงานในพื้นที่เคอร์เนลและส่งผลให้เกิดการเรียกระบบ

•ใช้แนวคิดของการเป็นเจ้าของ เฉพาะเธรดที่ปัจจุบันถือ mutex เท่านั้นที่สามารถปลดล็อกได้

• Mutex ไม่ซ้ำ (ข้อยกเว้น: PTHREAD_MUTEX_RECURSIVE)

•มักใช้ในการเชื่อมโยงกับตัวแปรเงื่อนไขและส่งผ่านเป็นอาร์กิวเมนต์เช่น pthread_cond_signal, pthread_cond_wait เป็นต้น

•ระบบ UNIX บางระบบอนุญาตให้ใช้ mutex โดยหลายกระบวนการแม้ว่าจะไม่สามารถใช้กับทุกระบบได้

สัญญาณ:

•นี่คือจำนวนเต็มเคอร์เนลที่เก็บรักษาค่าที่ไม่ได้รับอนุญาตให้ต่ำกว่าศูนย์

•มันสามารถใช้ในการประสานกระบวนการ

•ค่าเซมาฟอร์อาจถูกกำหนดเป็นค่าที่มากกว่า 1 ซึ่งในกรณีนี้ค่ามักจะระบุจำนวนทรัพยากรที่มีอยู่

•สัญญาณที่มีค่าถูก จำกัด 1 และ 0 จะเรียกว่าสัญญาณสัญญาณแบบไบนารี


0

Supporting ownership, maximum number of processes share lockและmaximum number of allowed processes/threads in critical sectionมีสามปัจจัยสำคัญที่กำหนดชื่อ / lockประเภทของวัตถุพร้อมกันกับชื่อทั่วไปของ เนื่องจากค่าของปัจจัยเหล่านี้เป็นไบนารี (มีสองสถานะ) เราจึงสามารถสรุปได้ในตารางเหมือนจริง 3 * 8

  • X (รองรับการเป็นเจ้าของ?): ไม่ (0) / ใช่ (1)
  • Y (กระบวนการแชร์ #):> 1 (∞) / 1
  • Z (# processes / threads ใน CA):> 1 (∞) / 1

  X   Y   Z          Name
 --- --- --- ------------------------
  0   ∞   ∞   Semaphore              
  0   ∞   1   Binary Semaphore       
  0   1   ∞   SemaphoreSlim          
  0   1   1   Binary SemaphoreSlim(?)
  1   ∞   ∞   Recursive-Mutex(?)     
  1   ∞   1   Mutex                  
  1   1   ∞   N/A(?)                 
  1   1   1   Lock/Monitor           

รู้สึกอิสระที่จะแก้ไขหรือขยายตารางนี้ฉันได้โพสต์เป็นตาราง ASCII ที่สามารถแก้ไขได้ :)

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