我有一个问题,我可以使用一些代码示例来帮助我,我觉得提供一些背景可能有所帮助。
我需要创建一个3队列引擎(在C#中,winforms)。 3个队列只包含一个"动作"宾语。动作被抛入引擎,并坚持使用最可用的"队列(基本上是具有最低计数的队列)。几乎所有的队列都可以离散地和异步地运行而不会造成任何伤害。然而,有一个"行动"可能发生的情况,以及那种类型的"行动"发生并确实冒泡到队列的前面,它必须:
添加了一个问题,即3个队列中的任何一个都可以锁定另一个队列。
有没有人有这方面的经验?
我希望如此,似乎有点痛苦:-)在此先感谢
答案 0 :(得分:3)
首先,我不建议使用三个队列。我建议使用一个队列,只有3个不同的任务从中读取。我还建议使用BlockingCollection<T>
(这只是ConcurrentQueue
的包装,因为它更容易使用。
至于其余部分,ReaderWriterLockSlim
(Thanks 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 Servy和ReaderWriterLock
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
}
}
}
当动作完成后,你释放所有三个锁,一切都恢复正常,每个线程都拥有自己的锁,并恢复动作。