Lock กับ Mutex ต่างกันอย่างไร? ทำไมถึงใช้แทนกันไม่ได้?
Lock กับ Mutex ต่างกันอย่างไร? ทำไมถึงใช้แทนกันไม่ได้?
คำตอบ:
lock
เป็นคีย์เวิร์ดคอมไพเลอร์ไม่ใช่คลาสหรืออ็อบเจ็กต์จริง เป็นกระดาษห่อหุ้มฟังก์ชันการทำงานของMonitor
คลาสและออกแบบมาเพื่อให้ใช้งานMonitor
ได้ง่ายขึ้นสำหรับกรณีทั่วไป
Monitor
(และlock
คำหลัก) จะเป็นดารินทร์กล่าวว่าถูก จำกัด AppDomain
ไปยัง ส่วนใหญ่เนื่องจากจำเป็นต้องมีการอ้างอิงไปยังที่อยู่หน่วยความจำ (ในรูปแบบของวัตถุที่สร้างอินสแตนซ์) เพื่อจัดการ "ล็อก" และรักษาข้อมูลประจำตัวของMonitor
Mutex
บนมืออื่น ๆ ที่เป็นกระดาษห่อสุทธิรอบสร้างระบบปฏิบัติการและสามารถนำมาใช้สำหรับการประสานทั้งระบบโดยใช้สตริงข้อมูล (แทนตัวชี้ไปยังข้อมูล) เป็นตัวระบุ mutexes สองตัวที่อ้างอิงสองสตริงในที่อยู่หน่วยความจำสองที่แตกต่างกันโดยสิ้นเชิง แต่มีข้อมูลเดียวกันจะใช้ mutex ระบบปฏิบัติการเดียวกัน
Mutex
สามารถทั้งในท้องถิ่นเพื่อเป็นกระบวนการหรือทั้งระบบ MSDN :
Mutexes มีสองประเภท: mutexes แบบโลคัลซึ่งไม่มีชื่อและตั้งชื่อระบบ mutexes mutex ในเครื่องมีอยู่ในกระบวนการของคุณเท่านั้น
นอกจากนี้ควรใช้ความระมัดระวังเป็นพิเศษ - มีรายละเอียดอยู่ในหน้าเดียวกันเช่นกัน - เมื่อใช้ mutex ทั้งระบบบนระบบที่มี Terminal Services
ความแตกต่างอย่างหนึ่งระหว่างMutex
และlock
คือการMutex
ใช้โครงสร้างระดับเคอร์เนลดังนั้นการซิงโครไนซ์จะต้องมีการเปลี่ยนพื้นที่เคอร์เนลของผู้ใช้เป็นอย่างน้อย
lock
- นั่นเป็นทางลัดไปสู่Monitor
คลาสในทางกลับกันพยายามหลีกเลี่ยงการจัดสรรทรัพยากรเคอร์เนลและการเปลี่ยนไปใช้รหัสเคอร์เนล (และมีขนาดเล็กลงและเร็วขึ้น - หากต้องหาโครงสร้าง WinAPI ที่มีลักษณะคล้ายกันก็จะเป็นได้CriticalSection
)
ความแตกต่างอื่น ๆ คือสิ่งที่ผู้อื่นชี้ให้เห็น: ชื่อ Mutex
สามารถใช้ข้ามกระบวนการได้
เว้นแต่จะมีความต้องการพิเศษหรือต้องการการซิงโครไนซ์ระหว่างกระบวนการก็จะดีกว่าที่จะยึดติดกับlock
(akaMonitor
) ˛
มีความแตกต่าง "เล็กน้อย" อื่น ๆ อีกหลายประการเช่นวิธีจัดการกับการละทิ้งเป็นต้น
เช่นเดียวกับที่ได้กล่าวเกี่ยวกับReaderWriterLock
และReaderWriterLockSlim
ใน 3.5 Semaphore
และใหม่SemaphoreSlim
ใน .NET 4.0 ฯลฯ มันเป็นความจริงว่าหลังxxSlim
เรียนไม่สามารถใช้เป็นทั้งระบบพื้นฐานซิงค์ แต่พวกเขาก็ไม่เคยหมายถึง - พวกเขาได้ "เท่านั้น" หมายความว่า เพื่อให้เร็วขึ้นและเป็นมิตรกับทรัพยากรมากขึ้น
ฉันใช้ Mutex เพื่อตรวจสอบว่าฉันมีสำเนาของแอปพลิเคชันที่ทำงานบนเครื่องเดียวกันหรือไม่
bool firstInstance;
Mutex mutex = new Mutex(false, @"Local\DASHBOARD_MAIN_APPLICATION", out firstInstance);
if (!firstInstance)
{
//another copy of this application running
}
else
{
//run main application loop here.
}
// Refer to the mutex down here so garbage collection doesn't chuck it out.
GC.KeepAlive(mutex);
มีคนพูดไปแล้วมากมาย แต่เพื่อให้ง่ายนี่คือสิ่งที่ฉันใช้
ล็อค -> ใช้งานง่ายกระดาษห่อหุ้มบนจอภาพล็อคข้ามเธรดใน AppDomain
mutex ที่ไม่มีชื่อ -> คล้ายกับการล็อกยกเว้นขอบเขตการล็อกมีมากกว่าและอยู่ใน AppDomain ในกระบวนการ
ชื่อว่า mutex -> ขอบเขตการล็อกเป็นมากกว่า mutex ที่ไม่มีชื่อและอยู่ระหว่างกระบวนการในระบบปฏิบัติการ
ตอนนี้มีตัวเลือกแล้วคุณต้องเลือกตัวเลือกที่เหมาะสมที่สุดในกรณีของคุณ
Mutex เป็นกระบวนการข้ามและจะมีตัวอย่างคลาสสิกของการไม่เรียกใช้แอปพลิเคชันมากกว่าหนึ่งอินสแตนซ์
ตัวอย่างที่ 2 คือบอกว่าคุณมีไฟล์และไม่ต้องการให้กระบวนการอื่นเข้าถึงไฟล์เดียวกันคุณสามารถใช้งาน Mutex ได้ แต่จำไว้ว่าสิ่งหนึ่งที่ Mutex เป็นระบบปฏิบัติการที่กว้างและไม่สามารถใช้ระหว่างสองกระบวนการระยะไกลได้
การล็อกเป็นวิธีที่ง่ายที่สุดในการป้องกันส่วนของรหัสของคุณและเป็นโดเมนเฉพาะของแอปคุณสามารถแทนที่การล็อกด้วยจอภาพได้หากต้องการการซิงโครไนซ์ที่ควบคุมได้มากขึ้น
ความแตกต่างเล็กน้อยอีกเล็กน้อยที่ไม่ได้กล่าวถึงในคำตอบ:
ในกรณีที่ใช้ล็อคคุณสามารถมั่นใจได้ว่าจะล็อค คลายเมื่อมีข้อยกเว้นเกิดขึ้นภายในบล็อกของล็อก
นั่นเป็นเพราะการล็อคใช้จอภาพใต้ฝากระโปรงและใช้วิธีนี้ :
object __lockObj = x;
bool __lockWasTaken = false;
try
{
System.Threading.Monitor.Enter(__lockObj, ref __lockWasTaken);
// Your code...
}
finally
{
if (__lockWasTaken) System.Threading.Monitor.Exit(__lockObj);
}
ดังนั้นไม่ว่าในกรณีใดล็อคจะถูกปลดและคุณไม่จำเป็นต้องปลดล็อคด้วยตนเอง (เช่นเดียวกับที่คุณทำกับ mutexes)
สำหรับ Locks คุณมักจะใช้วัตถุส่วนตัวเพื่อล็อค (และควรใช้ )
นี้ทำด้วยเหตุผลหลายประการ (ข้อมูลเพิ่มเติม:ดูคำตอบนี้และเอกสารอย่างเป็นทางการ )
ดังนั้นในกรณีของการล็อกคุณจะไม่สามารถ (เข้าถึงวัตถุที่ถูกล็อกจากภายนอกโดยบังเอิญ) และทำให้เกิดความเสียหายได้
แต่ในกรณีของ Mutex คุณสามารถทำได้เนื่องจากเป็นเรื่องปกติที่จะมี Mutex ซึ่งทำเครื่องหมายเป็นสาธารณะและใช้งานได้จากทุกที่