VB.NET多线程,阻塞线程直到收到通知

时间:2012-09-06 01:53:24

标签: vb.net multithreading events

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

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

我有几个线程都在不同的数据输入流上执行相同的任务。每个线程通过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框架类或代码示例)都将非常感激。如果我需要详细说明,请告诉我,我将尽我所能。

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

1 个答案:

答案 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