.net 构造/模式按代码段而不是按线程阻塞

发布于 2024-10-31 23:47:57 字数 611 浏览 2 评论 0原文

.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 处于“活动”状态。如果 Segment 1 正在执行,则另一个线程应该能够执行 Segment1,但不能执行 Segment2。

编辑2
考虑到所有的评论/回复和我的真实场景,我意识到要求 Segment2 由多线程访问有点疯狂。

Is there a construct or pattern in .net that defines a segment of code that can be accessed by multiple threads but blocks if any thread is in some other segment of code (and vice-versa)? For example:

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 ... 
    }     
}

Edit
Several threads should be able to access Segment1/Segment2 simultaneously (only one Segment being "active" at a time. If Segment 1 is executing, another thread should be able to execute Segment1 but not Segment2.

Edit 2

Given all the comments/replies and my real-world scenario, I realize that its a bit crazy to require Segment2 to be accessed by multiple-threads.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

旧城空念 2024-11-07 23:47:57

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

为了解决您的具体问题,.NET 甚至 Win32 中没有任何内容直接支持此锁定模型,但是您可以使用其他原语构建它。 我会考虑使用一对 ReaderWriterLockSlim 实例来保护每个资源。当线程进入 SegmentA 时,您将获得 A 上的写读锁和 B 写锁……反之亦然,对于进入 SegmentB 的线程也是如此。这将允许多个线程在每个段内执行,但不能同时执行

编辑鉴于您在问题评论中的答复,我更确信您需要考虑使用读取器/写入器锁定模型。您正在寻找的是一种保护资源的方法,这样当“编写者”正在工作(序列化字典)时,没有读者或其他编写者可以进入,并且当“读者”正在工作时,他们不会互相阻止,但会阻止所有其他编写者。这是读/写锁的经典案例。

编辑2现在我有了更多的时间,我认为有一点值得详细阐述。考虑锁的方式是它们保护数据资源(内存、文件等)而不是代码区域。事实上,我们需要定义一次只能有一个线程可以进入的代码关键部分,这一事实是一个实现细节,不应与共享资源的使用方式(并且必须受到保护)相混淆。在您的问题中,重点关注如何控制哪些线程可以进入代码的哪个部分,这误导了真正的问题:您试图保护哪些数据资源免受哪种更改的影响。一旦您从这个角度看待问题,就会更清楚哪种实现范例有意义。

这里有一些关于读取器/写入器锁定模型的好资源:

http://msdn.microsoft.com/en-us/magazine/cc163599.aspx

http://msdn.microsoft.com/en-us/library/bz6sth95.aspx

http://blogs.msdn.com/b/万塞姆/archive/2006/03/29/564854.aspx

This is a rather unusual model for protecting resources from improper concurrent access. I would first consider whether your use case can't be translated into an equivalent scenario where you can use simple locks. If you could provide more details on why you need this kind of locking scheme it may be possible for the community to offer other ideas.

To address your specific question, nothing in .NET or even Win32 directly supports this locking model, however you may be able to build it out of other primitives. I would look at using a pair of ReaderWriterLockSlim instances to protect each resource. As threads enter SegmentA you aquire a write read lock on A and a write lock B ... and vice verse for threads entering SegmentB. This would allow multiple threads to execute within each segment, but not at the same time.

EDIT: Given your reply in the comments to your question, I am more convinced you need to look at using a Reader/Writer locking model. What you're looking for is a way to protect a resource such that when "writers" are doing work (serializing the dictionary) no readers or other writers can enter and when "readers" are doing work they don't block each other but block all other writers. This is a classic case for reader/writer locks.

EDIT 2: Now that I've have more time, I think it's worth elaborating on one points. The way to think about locks is that they protect data resources (memory, files, etc) rather than areas of code. The fact that we need to define critical sections of code that only one thread at a time can enter is an implementation detail that one shouldn't confuse with how shared resources are used (and must be protected). In your question, the focus on how to control which threads can enter which section of code misdirects from the real problem: which data resources you are trying to protect against what kind of changes. Once you look at the problem from that perspective, it makes it clearer which implementation paradigms make sense.

Here are some good resources on reader/writer locking models:

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

无尽的现实 2024-11-07 23:47:57

根据您的编辑,听起来正确的方法是使用 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();
    }
}

Given your edit, it sounds like the proper approach would be to use a ReaderWriterLockSlim, since you really shouldn't be modifying the collection when Segment2 is running, and you shouldn't allow more than 1 Segment2 to run:

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();
    }
}
你曾走过我的故事 2024-11-07 23:47:57

有点像那样。

    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 锁定/

Sort of like that.

    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, it will not work with ReaderWriter locking/

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文