2

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

我需要创建 3 个队列的引擎(在 C# 中,winforms 中)。3 个队列仅包含一个“动作”对象。动作被扔进引擎,并坚持到“最可用”的队列(基本上是计数最少的队列)。队列几乎在所有时间都可以离散和异步运行而不会造成任何伤害。但是,可能会发生一种“动作”情况,当这种类型的“动作”发生并且确实冒泡到队列的前面时,它必须:

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

增加的问题是 3 个队列中的任何一个都可以锁定其他 2 个。

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

我希望如此,这似乎有点痛苦:-)提前谢谢

4

4 回答 4

3

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

至于其余的,ReaderWriterLockSlim感谢 Casperah)应该很容易处理它。Writer 需要独占锁,而 Reader 只锁定其他 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();
                }
            }
        }
    });
}
于 2012-11-13T22:16:33.713 回答
3

这是 Servy 推荐的单队列方法和CasperahReaderWriterLock建议的组合

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 被获取时,所有的 ReaderLocks 都被释放,并且一次只运行一个 WriterLock。

于 2012-11-13T22:14:29.600 回答
0

我谦虚的建议:

创建三个对象

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

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

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

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

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

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

于 2012-11-13T22:14:30.400 回答