ทำไมวัตถุล็อคจึงต้องเป็นแบบคงที่?


112

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

แต่ทำไมคง?

private static readonly object Locker = new object();

ในตอนท้ายฟิลด์จะใช้เฉพาะในชั้นเรียนของฉันเท่านั้นและฉันยังสามารถใช้สิ่งนี้แทน:

private readonly object Locker = new object();

มีคำแนะนำอะไรมั้ย?

อัพเดท:

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

private readonly object Locker = new object();

และนี่คือรหัส:

    private int _priceA;
    private int _priceB;
    private EventWaitHandle[] _waithandle;
    private readonly IService _service;

//ctor
public ModuleAViewModel(IService service)
    {
        _service = service;
        _modelA = new ModelA();
        _waithandle = new ManualResetEvent[2];
        _waithandle[0] = new ManualResetEvent(false);
        _waithandle[1] = new ManualResetEvent(false);
        LoadDataByThread();
    }


 private void LoadDataByThread()
        {
            new Thread(() =>
                           {
                               new Thread(() =>
                               {
                                   lock (Locker)
                                   {
                                       _priceA = _service.GetPriceA();
                                   }
                                   _waithandle[0].Set();
                               }).Start();

                               new Thread(() =>
                               {
                                   lock (Locker)
                                   {
                                       _priceB = _service.GetPriceB();
                                   }
                                   _waithandle[1].Set();
                               }).Start();

                               WaitHandle.WaitAll(_waithandle);
                               PriceA = _priceA;
                               PriceB = _priceB;
                           }).Start();
        }

ขอบคุณ


15
สำหรับความรู้ของฉันมักจะใช้แบบคงที่เพื่อทำให้อินสแตนซ์ไม่เชื่อเรื่องพระเจ้า หาก "MyWorkerClass" มีอยู่หลายอินสแตนซ์จะมีเพียงอินสแตนซ์เดียวเท่านั้นที่สามารถรันกับข้อมูลที่กำหนดได้ในแต่ละครั้ง (สมมติว่าใช้ทรัพยากรร่วมกันทั้งหมด)
Brad Christie

2
การแก้ไขขาดรายละเอียดที่สำคัญ: อยู่ที่ไหน_serviceและ_waithandleอยู่ที่ไหน? ตัวอย่าง? คงที่? อื่น ๆ ? ที่สามารถยกตัวอย่างเช่นจะจงใจตรงกันเข้าถึงเซิร์ฟเวอร์ระยะไกล ...
Marc Gravell

ถูกต้องด้วยการแก้ไขครั้งที่สอง: ใช่จากจุดสิ้นสุดนี้คุณสามารถล็อกต่ออินสแตนซ์ได้ มีอาจได้รับเหตุผลที่จะทำให้มันเป็นแบบคงที่แม้ว่า - ถ้า dev เดิมอยาก (ดังกล่าว) เพื่อเข้าถึงประสานเพื่อให้เซิร์ฟเวอร์เพียงได้รับคำขอเดียวในครั้งเดียวจาก AppDomain นี้ ... ฉันจะไม่ทราบว่าเป็นกรณีที่ หรือว่าเป็นเพียงอุบัติเหตุ
Marc Gravell

คำตอบ:


177

มันไม่ได้เป็น "มากทั่วไปจะใช้คงส่วนตัววัตถุอ่านได้อย่างเดียวสำหรับล็อคในหลายเธรด" - แต่มันเป็นเรื่องธรรมดาที่จะใช้ล็อคที่เหมาะสมเมล็ด / ได้รับการแต่งตั้ง staticบางครั้งที่เป็น บ่อยขึ้น IMO ก็ไม่ได้ - แต่เป็นตัวอย่างตาม

เวลาหลักที่คุณเห็นการstaticล็อกคือสำหรับแคชส่วนกลางหรือสำหรับการโหลดข้อมูลส่วนกลาง / singletons ที่รอการตัดบัญชี และในระยะหลังมีวิธีที่ดีกว่าการทำมันอยู่แล้ว

ดังนั้นมันขึ้นอยู่กับ: Lockerใช้ในสถานการณ์ของคุณอย่างไร? เป็นการปกป้องสิ่งที่เป็นตัวมันเองหรือไม่? ถ้าเป็นเช่นนั้นตัวล็อคควรเป็นแบบคงที่ หากมีการปกป้องสิ่งที่เป็นเช่นตามแล้ว IMO ล็อคควรจะยังเป็นเช่น based


24
คุณช่วยให้รายละเอียดเพิ่มเติมเกี่ยวกับวิธีที่ดีกว่าในการรอการโหลดข้อมูลส่วนกลางได้หรือไม่
bizi

ฉันมักจะใช้ static / volatile เพราะหากมีหลายที่ที่เป็นอินสแตนซ์ฉันยังคงต้องการควบคุมวิธีการ / ตัวแปรของฉันที่ถูกเข้าถึงด้วยวิธีที่ปลอดภัย หลายอินสแตนซ์อาจกำลังเข้าถึงทรัพยากรเดียวกันและฉันต้องการควบคุมสิ่งนั้น ฉันก็อยากเห็นสิ่งที่ดีกว่าของการทำเช่นนี้ คุณมีตัวแทนที่ดีและฉันมั่นใจว่าคำตอบของคุณจะดีพอ ๆ กันสำหรับฉันที่จะนำไปใช้ กรุณาตอบกลับ?
Andrew Simpson

82

ไม่จำเป็นต้องเป็นแบบคงที่ในความเป็นจริงบางครั้งก็ไม่ควรนิ่ง

ตัวแปรควรอยู่ในขอบเขตเดียวกับวิธีการที่คุณใช้ในการล็อก หากวิธีการเป็นแบบคงที่ตัวแปรควรเป็นแบบคงที่และหากวิธีการนั้นเป็นวิธีการของอินสแตนซ์ตัวแปรควรเป็นตัวแปรอินสแตนซ์

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


28
+1 สำหรับ "a-ha" ... คุณจะล็อกวิธีการทั้งหมดในทุกอินสแตนซ์ไม่ใช่เฉพาะเมธอดในอินสแตนซ์เดียวกัน
radarbob

3
@radarbob - รายละเอียดเล็กน้อย: คุณจะไม่ล็อควิธีการทั้งหมดที่คุณเพียงแค่ล็อคที่ลูกค้าสามารถสนใจได้มากขึ้นวิธีการต่างๆจะไม่ถูกล็อคเพียงแค่ใช้ mutex เท่านั้น
Erno

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

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

28

ขอบเขตและอายุการใช้งานของล็อคสามารถ / ควรขึ้นอยู่กับ 'สิ่งของ' ที่คุณต้องการล็อค ล็อคแบบคงที่ส่วนใหญ่ใช้เพื่อล็อคสิ่งที่คงที่


3
รายละเอียดเล็กน้อย: การล็อกไม่อยู่นิ่งวัตถุที่คุณใช้ระบุการล็อกนั้นเป็นแบบคงที่ รายละเอียดปลีกย่อยอื่น ๆ : คุณไม่ได้ล็อก "สิ่งของ"
Guffa

2
ใช่ฉันคิดว่าถ้าเราพยายามล็อค "สิ่ง" ผิด ๆ ไว้มันอาจจะใหญ่และแข็งแรงเกินไปและวันหนึ่งก็หนีไป
ProfK

12
@Guffa เป็นเรื่องแปลกในความคิดเห็นด้านบนคุณพูดถูกต้อง: "คุณมีความซับซ้อนมากเกินไป" ตอนนี้ฉันเห็น 1 นาทีก่อนที่จะพูดแบบนั้นดูเหมือนว่าคุณจะซับซ้อนเกินไป :)
Nicholas Petersen
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.