.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构造/模式按代码段阻塞,而不是按线程阻塞

这是一个非常不寻常的模型,用于保护资源免受不适当的并发访问。我将首先考虑您的用例是否不能转换为可以使用简单锁的等效场景。如果你能提供更多关于为什么你需要这种锁定方案的细节,社区可能会提供其他的想法。

为了解决你的具体问题,在。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锁定/