Peserta kembali mengunci C #

119

Akankah kode berikut mengakibatkan kebuntuan menggunakan C # di .NET?

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

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

    public void Bar()
    {
        lock(lockObj)
        { 
          // Do something 
        }
    }       
 }
Orang
sumber
6
Bolehkah kami mempertimbangkan untuk mengubah judul pertanyaan ini - mungkin menjadi sesuatu seperti yang baru-baru ini ditutup Mengapa kunci bersarang tidak menyebabkan kebuntuan? Sebenarnya, judul tersebut tampaknya hampir dirancang untuk mencegah orang menemukannya.
Jeff Sternal
12
Sebenarnya saya menemukan ini berdasarkan kata pencarian 'reentrant', dan itu menjawab pertanyaan saya. Jika itu pertanyaan dup, itu masalah yang berbeda ...
emfurry
Saya setuju dengan komentar @JeffSternal, pertanyaan ini mengasumsikan bahwa orang yang menelusuri pertanyaan tersebut sudah terbiasa dengan kunci "Re-entrant". Pertanyaan duplikasi lain yang menurut saya memiliki judul yang bagus untuk ini: stackoverflow.com/questions/3687505/…
Luis Perez

Jawaban:

148

Tidak, tidak selama Anda mengunci objek yang sama. Kode rekursif secara efektif sudah memiliki kunci sehingga dapat terus berlanjut tanpa hambatan.

lock(object) {...}adalah singkatan dari penggunaan kelas Monitor . Seperti yang ditunjukkan Marc , Monitormemungkinkan masuk kembali , jadi upaya berulang untuk mengunci objek di mana utas saat ini sudah memiliki kunci akan berfungsi dengan baik.

Jika Anda mulai mengunci objek yang berbeda , saat itulah Anda harus berhati-hati. Beri perhatian khusus pada:

  • Selalu dapatkan kunci pada sejumlah objek dalam urutan yang sama.
  • Selalu buka kunci dalam urutan yang berlawanan dengan cara Anda mendapatkannya.

Jika Anda melanggar salah satu aturan ini, Anda dijamin akan mendapatkan masalah kebuntuan di beberapa titik .

Berikut adalah satu halaman web bagus yang menjelaskan sinkronisasi utas di .NET: http://dotnetdebug.net/2005/07/20/monitor-class-avoiding-deadlocks/

Selain itu, kunci objek sesedikit mungkin. Pertimbangkan untuk menerapkan kunci berbutir kasar jika memungkinkan. Idenya adalah bahwa jika Anda dapat menulis kode Anda sedemikian rupa sehingga ada grafik objek dan Anda dapat memperoleh kunci pada akar grafik objek tersebut, maka lakukanlah. Ini berarti Anda memiliki satu kunci pada objek root tersebut dan oleh karena itu tidak perlu terlalu mengkhawatirkan urutan di mana Anda memperoleh / melepaskan kunci.

(Satu catatan lagi, contoh Anda secara teknis tidak rekursif. Agar menjadi rekursif, Bar()harus memanggil dirinya sendiri, biasanya sebagai bagian dari iterasi.)

Neil Barnwell
sumber
1
Apalagi di urutan yang berbeda.
Marc Gravell
6
Rekursi ulang; memang; untuk keuntungan Guy, istilahnya adalah peserta kembali
Marc Gravell
Terima kasih atas klarifikasi tentang terminologi tersebut - saya telah mengedit dan mengoreksi pertanyaannya.
Guy
Pertanyaan ini sepertinya mendapat sedikit perhatian jadi saya telah memperbarui jawaban saya dengan beberapa catatan lain yang saya dapatkan sejak saya pertama kali menulisnya.
Neil Barnwell
Sebenarnya, menurut saya urutan Anda melepaskan kunci tidak penting. Urutan yang Anda pilih pasti dilakukan, tetapi selama melepaskan kunci tidak tergantung pada apa pun (Anda dapat melepaskannya kapan saja), Anda akan baik-baik saja selama Anda melepaskan semua kunci yang telah Anda peroleh.
bobroxsox
20

Nah, Monitormemungkinkan masuk kembali, jadi Anda tidak bisa menemui jalan buntu ... jadi tidak: seharusnya tidak

Marc Gravell
sumber
7

Jika utas sudah memegang kunci, maka utas tidak akan menghalangi dirinya sendiri. Kerangka .Net memastikan hal ini. Anda hanya perlu memastikan bahwa dua utas tidak mencoba untuk mendapatkan dua kunci yang sama di luar urutan dengan jalur kode apa pun.

Benang yang sama dapat memperoleh kunci yang sama beberapa kali, tetapi Anda harus memastikan Anda melepaskan kunci dengan frekuensi yang sama seperti saat Anda memperolehnya. Tentu saja, selama Anda menggunakan kata kunci "kunci" untuk melakukannya, ini terjadi secara otomatis.

Jeffrey L. Whitledge
sumber
Perhatikan bahwa itu benar untuk monitor, tetapi belum tentu jenis kunci lainnya.
Jon Skeet
(Tidak ingin menyiratkan bahwa Anda tidak mengetahuinya, tentu saja - hanya saja itu perbedaan yang penting :)
Jon Skeet
Itu poin yang bagus. Saya sebenarnya akan mengubah "kunci" menjadi "monitor", tapi kemudian saya teralihkan. Dan malas. Dan perilaku ini juga berlaku untuk objek Windows mutex kernal, jadi saya pikir, cukup dekat!
Jeffrey L Whitledge
5

Tidak, kode ini tidak akan memiliki kunci buntu. Jika Anda benar-benar ingin membuat kebuntuan, yang paling sederhana membutuhkan setidaknya 2 sumber daya. Pertimbangkan skenario anjing dan tulang. 1. Seekor anjing memiliki kendali penuh atas 1 tulang sehingga anjing lain harus menunggu. 2. Minimal 2 anjing dengan 2 tulang diperlukan untuk menciptakan kebuntuan saat mereka mengunci tulang masing-masing dan mencari tulang orang lain juga.

.. seterusnya dan seterusnya n anjing dan m tulang dan menyebabkan kebuntuan yang lebih canggih.

Rishabh Jain
sumber