Иллюстрированный самоучитель по Visual Basic .NET

Взаимная блокировка

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) предназначено для простейшей передачи информации.

Если Вы заметили ошибку, выделите, пожалуйста, необходимый текст и нажмите CTRL + Enter, чтобы сообщить об этом редактору.