スレッド同期:共有リソースと異なるリソース番号の要求を伴うアクション

私は次の作業をしています:

同等のリソース(例えば、入力スロット)のプールと、このプールで実行される一連のアクションが存在する。

各アクションは別のスレッドで実行されます。

各アクションでは、使用可能な入力スロットの数が異なります。

私は次のタスクにセマフォーのようなものを使いたい:

すべてのアクションスレッドは同時に実行されます

このアクションは、必要な数の入力スロットが自由に使用できるときに実行されます

アクションが終了するとスロットは解放されます

セマフォーの負の初期値を設定することや、負の値になるまで値を減らすことができないため、通常のセマフォーを使用することはできません

したがって、WaitMultiple(int N)関数で "semaphore"が必要です。これは、 "リソース値がNに達するまで待ちます"

どのように私はそれを解決することができますどのような提案? 私はスレッドブロック/リリースを好む、私は能動的なループを余裕がない

3
私はC#セマフォーで働いていないので、私は答えることができません。しかし、ディスパッチのための別のスレッドでループを使用するとコストが高すぎるという結論にどのように到達したかに興味がありますか?
追加された 著者 Fdr,
アクティブなループによって、私は(;;)if(free_slots> N)のようなsmthを意味しました。あなたはどういう意味ですか?
追加された 著者 HtonS,
ブライアン、ありがとう=)
追加された 著者 HtonS,
+1:これは素晴らしい質問です。
追加された 著者 Brian Gideon,

2 答え

私はここでセマフォーが役に立つかどうかは分かりません。

私はあなたがCS/mutexで保護されたセクションでスレッドプールといくつかのコードでこれを行うことができると思います。アクションをコレクション(list/queue/stack、ディスパッチアルゴリズムに最適なもの)に置き、スロットカウントを初期化します。次に、アクションが完了してスロットが解放されるたびに、CSを入力し、現在のスロットカウントが与えられた場合に実行するアクションを決定します。これらのアクションをスレッドプールに提出し、スロットカウントを適切に減らしてCSを終了します。

'Slot-count'は単純な整数でも、複雑なクラスのコレクション数でもかまいません。

空きスロット数が増えるたびに、スレッドプールにディスパッチするアクションを決定する必要があります。スロットリリースによって複数のアクションを実行する可能性があるように思われるので、何らかのアルゴリズムが必要です。スロットの要件が最も高いアクションを実行しますか?

別のディスパッチャスレッドは必要ありませんし、確かにCPUループもありません!使用可能なスロットのためにいくつかのシンクロオブジェクトを待つことによってスロットターゲットを蓄積しようとするスレッドに基づく解決策は、デッドロックの危険性があることを恐れています - 多くのスレッドが部分的なスロット数で詰まり、また、あなたはアルゴリズムを微調整して、例えばスロット要求が高い状態で飢えている行動を防ぐことはできません。

3
追加された
ありがとう、マーティン!あなたの答えは助けになりました!
追加された 著者 HtonS,
+1:私はこの考えが好きです。私は、いくつかのスロットを必要とするアクションによって多くのスロットが飢えてしまうことを必要とするアクションを防ぐために、何らかの対策を想定しています。しかし、ええ、これは本当にスケーラブルな戦略のようです。
追加された 著者 Brian Gideon,
1つの可能性は、スロット要件と待機時間に基づいて、何らかの「優先度」によってアクションのリストを順序付けることです。返されたスロットは、リストの最初の項目に最初に適用されます。最終的には、大きなスロットカウントを必要とするアクションは、年齢を待っていたためリストの先頭に終わるので、スロットがあるまでそこに座ります。
追加された 著者 Martin James,

負のカウントの可能性を持つ独自の高速セマフォを実装することができます。たとえば、クラスMySemaphoreを次のように設定します。

public class MySemaphore
{
    private int size;//number of occupied resources
    private readonly int capacity;//total capacity

    public MySemaphore(int size, int capacity)
    {
        this.size = size;
        this.capacity = capacity;
    }

    public void Lock(int count)//acquire "count" resources
    {
        lock(this)
        {
            while(capacity - size < count)
            {
                Monitor.Wait(this);
            }
            size += count;
        }
    }        

    public void Unlock(int count)//release "count" resources
    {
        lock(this)
        {
            size -= count;
            Monitor.PulseAll(this);
        }
    }
}
1
追加された
ありがとう、チューダー。あなたの答えを前のものと組み合わせると思います。それは答えとして2つの投稿をチェックすることはできません
追加された 著者 HtonS,