2

始める前に、2つのことをお詫びする必要があります。一つは、簡潔に説明するのがとても難しいということです。二つ目は、私が働いている会社の性質上、やや漠然としている必要があるということです。

継承したアプリケーションの機能強化に取り組んでいます。これは非常に集中的なアプリケーションであり、私の会社の日常業務のかなりの部分を実行します。このため、私は変更できる範囲に制限されています。そうでない場合は、おそらく最初から書き直します。とにかく、これが私がする必要があることです:

同じタスクを実行するスレッドがいくつかありますが、データ入力ストリームは異なります。各スレッドは、ライセンスを支払う別のソフトウェアシステムからの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で.NETFramework3.5を使用しています。このためにすでに何らかのメカニズムが構築されている必要があると確信していますが、私が言ったように、どのキーワードを検索すべきか正確にはわかりません。私を正しい方向に向ける入力(つまり、使用する特定の.NET Frameworkクラスまたはコードサンプル)をいただければ幸いです。何か詳しく説明する必要がある場合は、お知らせください。できる限りのことをさせていただきます。

編集:私が抱えているもう1つの問題は、これらのチャネルをこのアプリケーションの外部から、ユーザーが手動で(またはユーザーが開始したイベントの結果として)オン/オフできることです。スレッドが使用しているときにチャネルがシャットダウンされることは関係ありません(例外がスローされ、次に通過したときに回復します。しかし、問題は、一定の数のスレッドが一定の数を争っているわけではないということです。チャネルの数(ユーザーが手動で1つをオンにすると、カウントが減るなど)両方の項目が可変であるため、外力がないという事実(つまり、このスレッドのセットの外側にあるもの、つまり利用可能なチャネル番号を決定するためにDBを介して処理を行う理由)

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 に答える