- Код: Выделить всё
Public Class ThreadInfoState
Private Shared mThreadDataSlot As LocalDataStoreSlot
Private Shared mThreads As Dictionary(Of Thread, ThreadInfoState)
Private Shared mLock As New Object
Shared Sub New()
mThreadDataSlot = Threading.Thread.AllocateDataSlot
End Sub
Public Shared Property ThreadData() As ThreadInfoState
Get
Return CType(Threading.Thread.GetData(mThreadDataSlot), ThreadInfoState)
End Get
Set(ByVal value As ThreadInfoState)
Threading.Thread.SetData(mThreadDataSlot, value)
SyncLock mLock
mThreads(Threading.Thread.CurrentThread) = value
End SyncLock
End Set
End Property
Public Shared ReadOnly Property ThreadData(ByVal nThread As Thread) As ThreadInfoState
Get
Static sCounter As Integer
sCounter += 1
If sCounter = 20 Then
sCounter = 0
CleanUpThreadsCollection()
End If
SyncLock mLock
Return mThreads(nThread)
End SyncLock
End Get
End Property
Private Shared Sub CleanUpThreadsCollection()
SyncLock mLock
Dim I As Thread
For Each I In mThreads.Keys
If Not I.IsAlive Then
mThreads.Remove(I)
End If
Next
End SyncLock
End Sub
'Other instance variables...
End Class
Итак, задача.
Есть некоторое многопоточное приложение. Потоки, которые выполняются в этом приложении периодически попадают в процедуры, которые изменяют значение свойства ThreadInfoState.ThreadData() на такое, которое им нужно. Свойтсво это имитироует ThreadStatic переменную. То есть для каждого потока значение этого свойства свое и не зависит от того что делают други потоки.
Тут вроде бы все просто и можно было бы даже не заморачиваться со свойствами и просто объявить ThreadStatic переменную ThreadData... Но есть одна проблемка.
Среди прочих потоков есть парочка, которой необходимо в определенные промежутки времени получать значения "состояния" других потоков.
Иными словами, мне нужно ReadOnly свойство ThreadData(ByVal nThread As Thread).
Вот тут начинаются некоторые трудности. Во первых, в .NET как и в windows нету "официальных" средств для чтения TLS другого потока. На сколько я понимаю, конечно. Если есть, скажите, это было бы здорово.
Единственный способ, который я вижу для решения проблемы - это такое, которое я тут привел в виде кода.
Иными словами, мы берем ассоциативный массив, в котором каждому потоку когда либо обращавшемуся к свойству ThreadData() сопоставляется соответствующий объект ThreadInfoState.
У этого способа есть куча минусов. Во первых, нужно периодически очищать коллекцию от умерших потоков. Это плохо. Во вторых, операция записи в TLS становится узкой изза синклока. Получается, что хоть TLS и является локальным для каждого потока писать в него одновременно нельзя(изза вероятности повредить коллекцию). Кроме того даже после того как всякая необходимость в классе отвалится он все равно будет держать в своей коллекции довольно много экземпляров потоков, которые уже может быть и умерли, да нет возможности проверить это.
Эту можно было бы решить, если бы у потока было событие "умирания". Но его нет. Кроме того(что меня удивило) класс Thread нельзя привести к типу WaitHandle(это можно считать отдельным вопросом, какой в этом смысл?)