2

在开始之前,我必须为两件事道歉。一是我很难用简洁的方式解释事情。二是由于我工作的公司的性质,我需要有点模糊。

我正在努力增强我继承的应用程序的功能。这是一个非常密集的应用程序,运行着我公司日常业务的很大一部分。因此,我仅限于我可以更改的范围——否则我可能会从头开始重写它。无论如何,这是我需要做的:

我有几个线程都执行相同的任务,但在不同的数据输入流上。每个线程通过来自另一个软件系统的 API 进行交互,我们支付许可以写入所谓的通道。不幸的是,我们只许可了一定数量的同时运行的频道,所以这个应用程序应该根据需要将它们打开和关闭。

每个线程都应该等待,直到有可用的通道,为自己锁定通道并执行其处理,然后释放通道。不幸的是,我不知道如何做到这一点,尤其是跨多个线程。我也真的不知道要在 Google 或这个网站上搜索什么,否则我可能会得到我的答案。这是我的想法:

处理通道号分布的类。每个线程调用这个类的一个成员。当它这样做时,它会进入一个队列并阻塞,直到通道处理类识别出我们有一个通道,向等待线程发出一个通道可用的信号并将通道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 框架类或代码示例)将不胜感激。如果我需要详细说明任何事情,请告诉我,我会尽我所能。

编辑:我遇到的另一个问题是,这些通道可以在此应用程序之外由用户手动打开/关闭(或作为用户启动事件的结果)。我不关心在线程使用通道时关闭通道(它会抛出异常,然后在下次通过时重新启动。但问题是没有恒定数量的线程争夺一个常数通道数(如果用户手动打开一个,则减少计数等)。这两项都是可变的,所以我不能依赖没有外力的事实(即,这组线程之外的东西,即为什么我通过我的数据库进行一些处理以确定可用的频道号)

4

1 回答 1

1

我会做什么:

  • System.Threading.ThreadSystem.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
于 2012-09-06T02:10:56.033 回答