2

質問があります。いくつかのコード例を参考にしてください。背景を説明するのに役立つと思います。

3つのキュー(C#ではwinforms)のエンジンを作成する必要があります。3つのキューには、単に「アクション」オブジェクトが含まれています。アクションはエンジンにスローされ、「最も利用可能な」キュー(基本的にはカウントが最も少ないキュー)に固執します。ほとんどの場合、キューは害を及ぼすことなく個別に非同期で実行できます。ただし、発生する可能性のある「アクション」状況が1つあり、そのタイプの「アクション」が発生してキューの先頭にバブルする場合は、次のことを行う必要があります。

  • 他のキューが現在のアクションを停止するのを待ちます
  • 現在のアクションが終了したら、ロック/一時停止します
  • 完了するまでアクションを単独で実行します
  • 他の2つのキューのロックを解除します。

3つのキューのいずれかが他の2つをロックする可能性があるという追加の問題があります。

誰かがこれの経験がありますか?

そうだといいのですが、少し辛そうです:-)よろしくお願いします

4

4 に答える 4

3

まず、3 つのキューを使用することはお勧めしません。1 つのキューを使用し、そこから 3 つの異なるタスクを読み取ることをお勧めします。また、BlockingCollection<T>(これは a の単なるラッパーであり、操作ConcurrentQueueが簡単です。

あとは、ReaderWriterLockSlim( Casperah さんに感謝) なら簡単に扱えるはずです。ライターは排他ロックを必要とし、リーダーは他のライターのみをロックアウトします。これはまさにあなたのユースケースです。

var queue = new BlockingCollection<Action>();

int numWorkers = 3;
ReaderWriterLockSlim throttler = new ReaderWriterLockSlim();


for (int i = 0; i < numWorkers; i++)
{
    Task.Factory.StartNew(() =>
    {
        foreach (Action nextAction in queue.GetConsumingEnumerable())
        {
            if (mustBeExectutedSerially(nextAction))
            {
                try
                {
                    throttler.EnterWriteLock();
                    nextAction();
                }
                finally
                {
                    throttler.ExitWriteLock();
                }
            }
            else
            {
                try
                {
                    throttler.EnterReadLock();
                    nextAction();
                }
                finally
                {
                    throttler.ExitReadLock();
                }
            }
        }
    });
}
于 2012-11-13T22:16:33.713 に答える
3

これは、Servy が推奨するシングル キュー アプローチと Casperah のReaderWriterLock提案を組み合わせたものです。

ReaderWriterLockSlim throttler = new ReaderWriterLockSlim();
for (int i = 0; i < numWorkers; i++)
{
    Task.Factory.StartNew(() =>
    {
        foreach (Action nextAction in queue.GetConsumingEnumerable())
        {
            if (mustBeExectutedSerially(nextAction))
            {
                try
                {
                    throttler.EnterWriteLock();
                    nextAction();
                }
                finally
                {
                    throttler.ExitWriteLock();
                }
            }
            else
            {
                try
                {
                    throttler.EnterReadLock();
                    nextAction();
                }
                finally
                {
                    throttler.ExitReadLock();
                }
            }
        }
    });
}
于 2012-11-13T23:01:45.793 に答える
2

System.Threading.ReaderWriterLockがあなたに代わって仕事をしてくれるようです。

通常のタスクはこれを行う必要があります:

readerWriterLock.AcquireReaderLock(timeout);
try
{
    RunNormalAction();
}
finally
{
     readerWriterLock.ReleaseReaderLock();
}

そして、高度なタスクはこれを行う必要があります:

readerWriterLock.AcquireWriterLock(timeout);
try
{
    RunSpecialAction();
}
finally
{
     readerWriterLock.ReleaseWriterLock();
}

必要な数のReaderLockを開始でき、期待どおりに実行され続けます。WriterLockが取得されると、すべてのReaderLockが解放され、一度に1つのWriterLockのみが実行されます。

于 2012-11-13T22:14:29.600 に答える
0

私の謙虚な暗示:

3つのオブジェクトを作成します

object threadlock1 = new object();
object threadlock2 = new object();
object threadlock3 = new object();

各スレッドは、アクションを実行する前に1つのオブジェクトのロックを取得します。

lock (threadlock1)  // On thread 1, for example
{ //Run Action }

THEアクションが発生すると、THEアクションを持つスレッドは、3つのオブジェクトのロックを取得する必要があります。これにより、他のスレッドが作業を終了するのを待ち、それ以上実行できなくなります。

lock (threadlock1)  // On thread 1, for example
{
 lock (threadlock2)
 {
  lock (threadlock3)
  {
    //Run THE Action 
  }
 }
}

アクションが終了したら、3つのロックをすべて解放すると、すべてが通常の状態に戻り、各スレッドが独自のロックを保持し、アクションを再開します。

于 2012-11-13T22:14:30.400 に答える