C# .net构造/模式按代码段而不是按线程阻塞
在.net中是否有一种结构或模式定义了一段代码,该段代码可以被多个线程访问,但如果任何线程位于其他代码段中(反之亦然),则会被阻塞?例如:C# .net构造/模式按代码段而不是按线程阻塞,c#,.net,multithreading,design-patterns,.net-4.0,C#,.net,Multithreading,Design Patterns,.net 4.0,在.net中是否有一种结构或模式定义了一段代码,该段代码可以被多个线程访问,但如果任何线程位于其他代码段中(反之亦然),则会被阻塞?例如: void SomeOperationA() { Block( B ) { Segment1: ... only executes if no threads are executing in Segment2 ... } } } void SomeOperationB() {
void SomeOperationA()
{
Block( B )
{
Segment1:
... only executes if no threads are executing in Segment2 ...
}
}
}
void SomeOperationB()
{
Block( A )
{
Segment2:
... only executes if no threads are executing in Segment1 ...
}
}
编辑多个线程应该能够同时访问段1/2(一次只有一个段处于“活动”状态)。如果段1正在执行,另一个线程应该能够执行段1,但不能执行段2。
编辑2
考虑到所有的评论/回复和我的真实场景,我意识到要求多线程访问Segment2有点疯狂。考虑到您的编辑,似乎正确的方法应该是使用,因为在Segment2运行时您确实不应该修改集合,并且您不应该允许超过1个Segm要运行的ent2:
private static ReaderWriterLockSlim readerLock = new ReaderWriterLockSlim();
void SomeOperationA()
{
try
{
readerLock.EnterReadLock();
// Segment1:
// ... only executes if no threads are executing in Segment2 ...
}
finally
{
readerLock.ExitReadLock();
}
}
void SomeOperationB()
{
try
{
readerLock.EnterWriteLock();
// Prevents multiple Segment2 from serializing, and prevents all Segment1 threads...
}
finally
{
readerLock.ExitWriteLock();
}
}
有点像这样
class Segments
{
public const int None = 0;
public const int Segm1 = 1;
public const int Segm2 = 2;
}
int currentSegm = 0;
int segm1counter = 0;
int segm2counter = 0;
object segm1lock = new object();
object segm2lock = new object();
void SomeOperationA()
{
while (
Interlocked.CompareExchange(ref currentSegm, Segments.Segm1, Segments.Segm1) != Segments.Segm1
&&
Interlocked.CompareExchange(ref currentSegm, Segments.Segm1, Segments.None) != Segments.None
)
{
Thread.Yield();
}
Interlocked.Increment(ref segm1counter);
try
{
//Segment1:
//... only executes if no threads are executing in Segment2 ...
}
finally
{
lock (segm1lock)
{
if (Interlocked.Decrement(ref segm1counter) == 0)
currentSegm = Segments.None;
}
}
}
void SomeOperationB()
{
while (
Interlocked.CompareExchange(ref currentSegm, Segments.Segm2, Segments.Segm2) != Segments.Segm2
&&
Interlocked.CompareExchange(ref currentSegm, Segments.Segm2, Segments.None) != Segments.None
)
{
Thread.Yield();
}
Interlocked.Increment(ref segm2counter);
try
{
//Segment2:
//... only executes if no threads are executing in Segment2 ...
}
finally
{
lock (segm2lock)
{
if (Interlocked.Decrement(ref segm2counter) == 0)
currentSegm = Segments.None;
}
}
}
OK,这将不适用于读写器锁定//P>< P> <强>这是一个非常不寻常的模型来保护资源不正确的并发访问。< /强>我首先考虑你的用例不能转化成一个等价的场景,你可以使用简单的锁。对于锁定方案,社区可能会提供其他想法
为了解决您的具体问题,.NET甚至Win32中都不直接支持此锁定模型,但是您可以用其他原语构建它。我将考虑使用一对实例来保护每个资源。当线程进入段a时,您将在a上获得写读锁,在B上获得写锁…反之亦然这将允许多个线程在每个段内执行,但不能同时执行 编辑:鉴于您在对问题的评论中的回答,我更确信您需要考虑使用读写器锁定模型。您要寻找的是一种保护资源的方法,这样当“编写者”正在工作时(序列化词典),没有读者或其他编写者可以进入,并且“读卡器”正在工作,它们不会相互阻止,而是阻止所有其他写入程序。这是读写器锁定的典型情况 编辑2:现在我有更多的时间了,我认为有一点值得详细说明。考虑锁的方式是它们保护数据资源(内存、文件等)事实上,我们需要定义一次只有一个线程可以进入的关键代码部分,这是一个实现细节,我们不应该混淆共享资源的使用方式(并且必须加以保护)。在您的问题中,重点是如何控制哪些线程可以进入与实际问题不符的代码部分:您正试图保护哪些数据资源以防发生什么样的更改。一旦您从这个角度看待问题,它将使您更清楚哪些实现范例是有意义的 这里有一些关于读写器锁定模型的好资源:几个线程可以同时执行Segment2吗?听起来像是饥饿的处方。@SFun28:这在现实世界中的应用是什么?以下是现实世界中的场景:Segment2将ConcurrentDictionary序列化到磁盘。这种情况时有发生。序列化时,我们必须确保字典是稳定的。Segment1读取和/或r更改数据。它是线程安全的,因为ConcurrentDictionary是线程安全的。我们希望在Segment1中获得高吞吐量,但如果执行Segment2,我们希望停止显示。如果我们尝试执行Segment2,我们希望在完成Segment1执行之前保持不变。希望这有帮助。添加到我的“真实世界”"上面的场景:调用代码不会独占段1-可能段1会在一段时间内受到重击,然后调用段2,依此类推。机制只是为了安全措施。他没有说段2不能同时执行。如果是真的,简单的
lock
不会有帮助。@Andrey:是的-I如果这是一个要求,事情会变得有点棘手…对不起,我是想包括这一点。是的,两个线程应该能够同时执行段1/2(但不能同时执行两个段!)SomeOperationB()
不能同时执行。它们应该是一样的。@Andrey:鉴于OPs对目标的评论,我不相信这是真的……我认为这不寻常的是多线程访问Segment2。如果我们说一次只有一个线程可以访问Segment2,但满足所有其他要求,我认为这只会降低到一个级别ReaderWriterLockSlim,对吗?它不适用于ReaderWriterLockSlim
,原因如下。您不能同时输入写锁。这将成为互斥,最终只有一个线程能够执行段。如前所述,这对ReaderWriterLock不起作用。一旦您获得写锁,您就可以预写释放两个线程来模拟执行该块…@SFun28:是的,我相信这是正确的。但是,我鼓励这种减少,因为它会让你进入已知的领域,而不是在野外使用锁定。@Reed Copsey:是的,我相信你是对的。我会更新我的答案。我曾经按照这些思路思考过-但是写锁阻止两个线程同时执行,这有效地将其转化为一个“锁”调用。非常感谢您为我的原始帖子编写了一个解决方案。我现在意识到我的原始场景非常疯狂。@SFun28这是一个有趣的谜题。我没有深入了解根本原因。