ล็อกการเข้าใหม่ใน C #


119

รหัสต่อไปนี้จะส่งผลให้เกิดการหยุดชะงักโดยใช้ C # บน. NET หรือไม่?

 class MyClass
 {
    private object lockObj = new object();

    public void Foo()
    {
        lock(lockObj)
        { 
             Bar();
        }
    }

    public void Bar()
    {
        lock(lockObj)
        { 
          // Do something 
        }
    }       
 }

6
เราอาจพิจารณาเปลี่ยนชื่อคำถามนี้ - อาจจะเป็นคำถามที่เพิ่งปิดไปทำไมการล็อกที่ซ้อนกันจึงไม่ทำให้เกิดการชะงักงัน ตามชื่อเรื่องดูเหมือนว่าเกือบจะออกแบบมาเพื่อป้องกันไม่ให้ผู้คนค้นพบ
Jeff Sternal

12
อันที่จริงฉันพบสิ่งนี้ตามคำค้นหา 'reentrant' และมันตอบคำถามของฉัน หากเป็นคำถามที่ถูก
หลอก

ฉันเห็นด้วยกับ @JeffSternal ความคิดเห็นคำถามนี้ถือว่าผู้ที่ค้นหาคำถามคุ้นเคยกับการล็อก "Re-entrant" อยู่แล้ว อีกคำถามเกี่ยวกับการทำซ้ำที่ฉันคิดว่ามีชื่อที่ดีสำหรับสิ่งนี้: stackoverflow.com/questions/3687505/…
Luis Perez

คำตอบ:


148

ไม่ไม่ตราบเท่าที่คุณกำลังล็อกวัตถุเดียวกัน รหัสเรียกซ้ำมีประสิทธิภาพอยู่แล้วและสามารถดำเนินการต่อได้โดยไม่ จำกัด

lock(object) {...}เป็นชวเลขสำหรับการใช้คลาสMonitor ดังที่Marc ชี้ให้เห็นว่าMonitorอนุญาตให้กลับเข้ามาใหม่ได้ดังนั้นความพยายามซ้ำ ๆ เพื่อล็อควัตถุที่เธรดปัจจุบันมีการล็อกอยู่แล้วจะใช้ได้ดี

หากคุณเริ่มต้นในการล็อคที่แตกต่างกันวัตถุที่เมื่อคุณจะต้องระมัดระวัง ให้ความสนใจเป็นพิเศษกับ:

  • รับการล็อกบนวัตถุจำนวนหนึ่งในลำดับเดียวกันเสมอ
  • ปลดล็อคในลำดับย้อนกลับเสมอว่าคุณได้มาอย่างไร

ถ้าคุณทำลายทั้งกฎเหล่านี้คุณสวยรับประกันมากที่จะได้รับปัญหาการหยุดชะงักในบางจุด

นี่คือหนึ่งหน้าเว็บที่ดีที่อธิบายการซิงโครไนซ์เธรดใน. NET: http://dotnetdebug.net/2005/07/20/monitor-class-avoiding-deadlocks/

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

(หมายเหตุเพิ่มเติมอีกประการหนึ่งตัวอย่างของคุณไม่ได้เกิดซ้ำในทางเทคนิคหากต้องการเรียกซ้ำBar()จะต้องเรียกตัวเองโดยทั่วไปเป็นส่วนหนึ่งของการวนซ้ำ)


1
โดยเฉพาะในลำดับที่แตกต่างกัน
Marc Gravell

6
การเรียกซ้ำ; แน่นอน; เพื่อผลประโยชน์ของ Guy คำนี้เป็นผู้เข้าใหม่
Marc Gravell

ขอบคุณสำหรับคำชี้แจงเกี่ยวกับคำศัพท์ - ฉันได้แก้ไขและแก้ไขคำถามแล้ว
Guy

คำถามนี้ดูเหมือนจะได้รับความสนใจไม่น้อยดังนั้นฉันจึงอัปเดตคำตอบของฉันด้วยบันทึกย่ออื่น ๆ ที่ฉันคิดขึ้นตั้งแต่ฉันเขียนครั้งแรก
Neil Barnwell

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


7

หากเธรดมีการล็อคอยู่แล้วมันจะไม่ปิดกั้นตัวเอง กรอบงาน. Net ช่วยให้มั่นใจได้ คุณต้องตรวจสอบให้แน่ใจว่าเธรดสองเธรดไม่ได้พยายามที่จะได้รับการล็อกสองตัวเดียวกันจากลำดับไม่ว่าจะเป็นรหัสพา ธ ใดก็ตาม

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


โปรดทราบว่าเป็นจริงสำหรับจอภาพ แต่ไม่จำเป็นต้องมีการล็อกแบบอื่น
Jon Skeet

(ไม่อยากบอกเป็นนัยว่าคุณไม่รู้แน่นอน - นั่นเป็นความแตกต่างที่สำคัญ :)
Jon Skeet

นั่นเป็นจุดที่ดี จริงๆแล้วฉันจะเปลี่ยน "ล็อก" เป็น "มอนิเตอร์" ตลอด แต่แล้วฉันก็เสียสมาธิ และขี้เกียจ. และพฤติกรรมยังเป็นจริงสำหรับวัตถุเคอร์เนลของ Windows mutex ดังนั้นฉันจึงคิดว่าใกล้พอ!
Jeffrey L Whitledge

5

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

.. เรื่อย ๆ ๆ ๆ ๆ ๆ ๆ ๆ ๆ ๆ ๆ ๆ ๆ ๆ ๆ ๆ ๆ ๆ ๆ ๆ ๆ ๆ ๆ ๆ ๆ ๆ ๆ ๆ ๆ ๆ ๆ ๆ ๆ ๆ ไป

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