#net #многопоточность #vbnet
Код из вопроса Насколько случайны данные, сгенерированные таким образом? упал: Т. е. в одном из методов произошёл вызов Release семафора, когда семафор был свободен. Imports System.Threading Module All Dim Value1 As Integer, Value2 As Integer Dim Sem1 As New SemaphoreSlim(1, 1), Sem2 As New SemaphoreSlim(1, 1) Dim Count As Integer Private Sub Inc(SemA As SemaphoreSlim, SemB As SemaphoreSlim, ByRef Value As Integer) Do Thread.Sleep(0) SemA.Wait() Interlocked.Increment(Count) SemB.Wait() Interlocked.Decrement(Count) Interlocked.Increment(Value) If SemB.CurrentCount = 0 Then SemB.Release() Else Interlocked.Increment(Count) If SemA.CurrentCount = 0 Then SemA.Release() Else Interlocked.Increment(Count) Loop End Sub Private Sub Init() Call (New Thread(Sub() Inc(Sem1, Sem2, Value1))).Start() Call (New Thread(Sub() Inc(Sem2, Sem1, Value2))).Start() End Sub Public Function GetRandBit() As Integer If Thread.VolatileRead(Count) = 2 Then Thread.VolatileWrite(Value1, 0) Thread.VolatileWrite(Value2, 0) Interlocked.Decrement(Count) Sem2.Release() End If Do Until Thread.VolatileRead(Count) = 2 Thread.Sleep(16) Loop Return Thread.VolatileRead(Value1) And 1 End Function Sub Main() Init() Do Console.Write(GetRandBit()) Loop End Sub End Module Указанный в исключении метод _Lambda$__7-1 это метод второго потока: [SpecialName] internal void _Lambda\u0024__7\u002D1() { All.Inc(All.Sem2, All.Sem1, ref All.Value2); } Из-за чего могла произойти такая ошибка? Насколько я представляю, Sem2.Release() из GetRandBit вызывается только если оба потока захватили по первой блокировке и никак не может возникнуть между проверкой на количество блокировок и вызовом Release. На момент вызова Release одним из двух потоков, он владеет обеими блокировками и никто посторонний семафоры не трогает. Что могло пойти не так в этой схеме?
Ответы
Ответ 1
Похоже, всё-таки разобрался. Последовательность такая: Поток 2 владеет блокировкой 2 (1/2) Поток 1 владеет блокировкой 1 (1/2) Возникает дедлок (1/2) Управляющий поток снимает блокировку 2 (1/*) Поток 1 захватывает блокировку 2 (12/*) Поток 1 выполняет инкремент (12/*) Поток 1 снимает блокировку 2 (1/*) Поток 1 снимает блокировку 1 (0/*) Поток 2 захватывает блокировку 1 (0/*1) Поток 2 выполняет инкремент (0/*1) Поток 2 снимает блокировку 1 (0/*) Поток 1 захватывает блокировку 1 (1/*) Поток 1 захватывает блокировку 2 (12/*) Поток 2 проверяет наличие блокировки 2 (12/*) Блокировка есть, но поток 2 не знает, что она чужая Поток 1 делает инкремент (12/*) Поток 1 снимает блокировку 2 (1/*) Поток 2 пытается снять блокировку 2 и падает В скобках обозначено владение блокировками: 1 - захвачена блокировка 1 и поток находится внутри её блока 2 - захвачена блокировка 2 и поток находится внутри её блока * - блокировка 2 НЕ захвачена, но поток находится внутри её блока 0 - захваченных блокировок нет и поток не находится внутри какого-либо блока
Комментариев нет:
Отправить комментарий