Взаимная блокировка
39 Public Class Knife 40 Private Shared mKnifeAvailable As Boolean = True 41 Private Shared mOwner As String ="Nobody" 42 Private Readonly Property OwnsUtensi1() As String 43 Get 44 Return mOwner 45 End Get 46 End Property 47 Public Sub GrabKnifetByVal a As Programmer) 48 Console.WriteLine(Thread.CurrentThread.Name & _ "trying to grab the knife.") 49 Console.WriteLine(Me.OwnsUtensil & "has the knife.") 50 Monitor.Enter(Me) 'SyncLock (aKnife)' 51 If mKnifeAvailable Then 52 mKnifeAvailable = False 53 a.HasKnife = True 54 mOwner = a.MyName 55 Console.WriteLine(a.MyName&"just got the knife.waiting") 56 Try Thread.Sleep(100) Catch e As Exception Console.WriteLine (e.StackTrace) End Try 57 End If 58 Monitor.Exit(Me) 59 End Sub 60 End Class 61 Public Class Programmer 62 Private mName As String 63 Private Shared mFork As Fork 64 Private Shared mKnife As Knife 65 Private mHasKnife As Boolean 66 Private mHasFork As Boolean 67 Shared Sub New() 68 mFork = New Fork() 69 mKnife = New Knife() 70 End Sub 71 Public Sub New(ByVal theName As String) 72 mName = theName 73 End Sub 74 Public Readonly Property MyName() As String 75 Get 76 Return mName 77 End Get 78 End Property 79 Public Property HasKnife() As Boolean 80 Get 81 Return mHasKnife 82 End Get 83 Set(ByVal Value As Boolean) 84 mHasKnife = Value 85 End Set 86 End Property 87 Public Property HasFork() As Boolean 88 Get 89 Return mHasFork 90 End Get 91 Set(ByVal Value As Boolean) 92 mHasFork = Value 93 End Set 94 End Property 95 Public Sub Eat() 96 Do Until Me.HasKnife And Me.HasFork 97 Console.Writeline(Thread.CurrentThread.Name&"is in the thread.") 98 If Rnd() < 0.5 Then 99 mFork.GrabFork(Me) 100 Else 101 mKnife.GrabKnife(Me) 102 End If 103 Loop 104 MsgBox(Me.MyName & "can eat!") 105 mKnife = New Knife() 106 mFork= New Fork() 107 End Sub 108 End Class
Основная процедура Main (строки 4-16) создает два экземпляра класса Programmer и затем запускает два потока для выполнения критического метода Eat класса Programmer (строки 95-108), описанного ниже. Процедура Main задает имена потоков и запускает их; вероятно, все происходящее понятно и без комментариев.
Интереснее выглядит код класса Fork (строки 17-38) (аналогичный класс Knife определяется в строках 39-60). В строках 18 и 19 задаются значения общих полей, по которым можно узнать, доступна ли в данный момент вилка, и если нет – кто ею пользуется. ReadOnly-свойство OwnUtensi1 (строки 20-24) предназначено для простейшей передачи информации.