.net构造/模式按代码段阻塞,而不是按线程阻塞
本文关键字:线程 段阻塞 构造 模式 代码 net | 更新日期: 2023-09-27 17:49:43
是否有一个结构或模式在。net中定义了一个代码段,可以由多个线程访问,但块,如果任何线程是在一些其他代码段(反之亦然)?例如:
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 ...
}
}
编辑
几个线程应该能够同时访问Segment1/Segment2(一次只有一个Segment处于"活动"状态)。如果段1正在执行,另一个线程应该能够执行段1,但不能执行段2。
编辑2
考虑到所有的评论/回复和我的现实世界场景,我意识到要求多线程访问Segment2有点疯狂。
这是一个非常不寻常的模型,用于保护资源免受不适当的并发访问。我将首先考虑您的用例是否不能转换为可以使用简单锁的等效场景。如果你能提供更多关于为什么你需要这种锁定方案的细节,社区可能会提供其他的想法。
为了解决你的具体问题,在。net甚至Win32中都没有直接支持这种锁定模型,但是你可以用其他原语来构建它。我会考虑使用一对。ReaderWriterLockSlim
实例来保护每个资源。当线程进入段a时,你在段a上获得一个写读锁和一个写锁。进入段b的线程反之亦然。这将允许多个线程在每个段内执行,但不能同时执行
EDIT: 鉴于您在对问题的评论中的回复,我更确信您需要考虑使用Reader/Writer锁定模型。你正在寻找的是一种保护资源的方法,当"写入器"正在工作(序列化字典)时,没有读取器或其他写入器可以进入,当"读取器"正在工作时,它们不会相互阻塞,而是阻塞所有其他写入器。这是一个典型的读/写锁案例。
: 既然我有更多的时间,我认为有一点值得详细说明。考虑锁的方式是,它们保护数据资源(内存、文件等),而不是代码区域。我们需要定义一次只有一个线程可以进入的关键代码段,这是一个实现细节,不应该与如何使用共享资源(必须受到保护)混淆。在您的问题中,关注于如何控制哪些线程可以进入哪些代码段,这偏离了实际问题:您试图保护哪些数据资源以防止哪种类型的更改。一旦您从这个角度看待问题,就会更清楚哪些实现范例是有意义的。
这里有一些很好的关于读写锁模型的资源:
http://msdn.microsoft.com/en-us/magazine/cc163599.aspx http://msdn.microsoft.com/en-us/library/bz6sth95.aspx http://blogs.msdn.com/b/vancem/archive/2006/03/29/564854.aspx对于您的编辑,听起来正确的方法是使用ReaderWriterLockSlim,因为您真的不应该在Segment2运行时修改集合,并且您不应该允许超过1个Segment2运行:
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;
}
}
}
好的,它不能工作与ReaderWriter锁定/