在开始之前,我必须为两件事道歉。一个是我很难以简洁的方式解释事物。第二,由于我工作的公司的性质,我需要有些模糊。
我正致力于增强我继承的应用程序的功能。这是一个非常密集的应用程序,它运行着我公司日常业务的很大一部分。因此,我受限于我可以改变的范围 - 否则我可能会从头开始重写它。无论如何,这是我需要做的:
我有几个线程都在不同的数据输入流上执行相同的任务。每个线程通过API从我们支付许可的另一个软件系统进行交互,以写出所谓的通道。不幸的是,我们只获得了一定数量的并发运行频道的许可,所以这个应用程序应该根据需要关闭它们。
每个线程应该等到有可用的通道,为自己锁定通道并执行其处理,然后释放通道。不幸的是,我不知道如何做到这一点,尤其是跨多个线程。我也不知道要搜索谷歌或这个网站的内容,或者我可能有我的答案。这是我的想法:
处理频道号码分配的类。每个线程都会调用此类的成员。当它执行此操作时,它将进入队列并阻塞,直到通道处理类识别出我们有一个通道,向等待线程发出通道可用信号并向其传递通道ID。我不知道从哪里开始查看。下面我有一些可怕的写PsuedoCode,我认为它会如何工作。
Public Class ChannelHandler
Private Shared WaitQueue as New Queue(of Thread)
'// calling thread adds itself to the queue
Public Shared Sub WaitForChannel(byref t as thread)
WaitQueue.enqueue(t)
End Sub
Public Shared Sub ReleaseChannel(chanNum as integer)
'// my own processing to make the chan num available again
End Sub
'// this would be running on a separate thread, polling my database
'// for an available channel, when it finds one, somehow signal
'// the first thread in the queue that its got a channel and here's the id
Public Shared Sub ChannelLoop()
while true
if WaitQueue.length > 0 then
if thereIsAChannelAvailable then '//i can figure this out my own
dim t as thread = ctype(WaitQueue.dequeue(), Thread)
lockTheChannel(TheAvailableChannelNumber) 'performed by me
'// signal the thread, passing it the channel number
t => SignalReady(theAvailableChannelNumber) '// how to signal?
end if
end if
end while
End Sub
End Class
然后
'// this inside the function that is doing the processing:
ChannelHandler.requestChannel(CurrentThread)
while (waitingForSignal) '// how?
block '// how?
dim channelNumber as int => getChannelNumberThatWasSignaledBack
'// perform processing with channelNumber
ChannelHandler.ReleaseChannel(channelNumber)
我正在使用VB.NET中的.NET Framework 3.5。我确信必须有一些已经为此构建的机制,但正如我所说,我不知道究竟应该搜索哪些关键字。任何指向正确方向的输入(即要使用的特定.NET框架类或代码示例)都将非常感激。如果我需要详细说明,请告诉我,我将尽我所能。
编辑:我遇到的另一个问题是这些频道可以由用户手动(或由于用户发起的事件)从该应用程序外部打开/关闭。我并不关心在线程使用它时关闭一个通道(它会抛出一个异常,然后在下次通过时重新启动。但问题是没有一个恒定数量的线程争夺一个常量通道数量(如果用户手动打开一个,计数减少等)。两个项目都是可变的,所以我不能依赖于没有外力的事实(即,这组线程之外的东西,这是为什么我通过我的数据库进行一些处理以确定可用的频道号)
答案 0 :(得分:1)
我会做什么:
System.Threading.Thread
切换为System.Threading.Tasks.Task
类。Task
,但List(Of Task)
(或者,在您的示例中,Queue(Of Task)
)计数大于允许的最大值,请使用Task.WaitAny方法修改强>
当我在手机上回答上一个块时(编写代码非常具有挑战性),现在让我写一个关于如何做的例子:
Imports System.Threading.Tasks
Imports System.Collections.Generic
Public Class Sample
Private Const MAXIMUM_PERMITTED As Integer = 3
Private _waitQueue As New Queue(Of Task)
Public Sub AssignChannel()
Static Dim queueManagerCreated As Boolean
If Not queueManagerCreated Then
Task.Factory.StartNew(Sub() ManageQueue())
queueManagerCreated = True
End If
Dim newTask As New Task(Sub()
' Connect to 3rd Party software
End Sub)
SyncLock (_waitQueue)
_waitQueue.Enqueue(newTask)
End SyncLock
End Sub
Private Sub ManageQueue()
Dim tasksRunning As New List(Of Task)
While True
If _waitQueue.Count <= 0 Then
Threading.Thread.Sleep(10)
Continue While
End If
If tasksRunning.Count > MAXIMUM_PERMITTED Then
Dim endedTaskPos As Integer = Task.WaitAny(tasksRunning.ToArray)
If endedTaskPos > -1 AndAlso
endedTaskPos <= tasksRunning.Count Then
tasksRunning.RemoveAt(endedTaskPos)
Else
Continue While
End If
End If
Dim taskToStart As Task
SyncLock (_waitQueue)
taskToStart = _waitQueue.Dequeue()
End SyncLock
tasksRunning.Add(taskToStart)
taskToStart.Start()
End While
End Sub
End Class