三个c#并发队列 - 如何在需要执行特定操作时暂停它们?

时间:2012-11-13 22:03:34

标签: c# winforms locking queue

我有一个问题,我可以使用一些代码示例来帮助我,我觉得提供一些背景可能有所帮助。

我需要创建一个3队列引擎(在C#中,winforms)。 3个队列只包含一个"动作"宾语。动作被抛入引擎,并坚持使用最可用的"队列(基本上是具有最低计数的队列)。几乎所有的队列都可以离散地和异步地运行而不会造成任何伤害。然而,有一个"行动"可能发生的情况,以及那种类型的"行动"发生并确实冒泡到队列的前面,它必须:

  • 等待其他队列停止当前的操作
  • 在完成当前操作
  • 时锁定/暂停它们
  • 单独执行操作直到完成
  • 释放其他2个队列的锁定。

添加了一个问题,即3个队列中的任何一个都可以锁定另一个队列。

有没有人有这方面的经验?

我希望如此,似乎有点痛苦:-)在此先感谢

4 个答案:

答案 0 :(得分:3)

首先,我不建议使用三个队列。我建议使用一个队列,只有3个不同的任务从中读取。我还建议使用BlockingCollection<T>(这只是ConcurrentQueue的包装,因为它更容易使用。

至于其余部分,ReaderWriterLockSlimThanks Casperah)应该很容易处理。一个Writer需要一个独占锁,而一个读者只能锁定其他编写器,这正是你的用例。

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();
                }
            }
        }
    });
}

答案 1 :(得分:3)

这是single queue approach recommended by ServyReaderWriterLock suggestion by Casperah的组合。

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();
                }
            }
        }
    });
}

答案 2 :(得分:2)

似乎System.Threading.ReaderWriterLock会为你完成这项工作。

正常任务应该这样做:

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

高级任务应该这样做:

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

您可以根据需要启动任意数量的ReaderLocks,它们将按预期继续运行。 获取WriterLock后,所有ReaderLocks都已释放,一次只能运行一个WriterLock。

答案 3 :(得分:0)

我谦虚的消化:

创建三个对象

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

每个线程在运行任何操作之前获取对一个对象的锁定。

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

当动作到来时,具有THE动作的线程必须锁定三个对象,从而等待其他线程完成其工作,并阻止它们再做任何事情。

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

当动作完成后,你释放所有三个锁,一切都恢复正常,每个线程都拥有自己的锁,并恢复动作。