.net конструкция / шаблон для блокировки по сегментам кода, а не по потокам - PullRequest
4 голосов
/ 12 апреля 2011

Есть ли в .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 ... 
    }     
}

Редактировать
Несколько потоков должны иметь возможность доступа к Сегменту 1 / Сегменту 2 одновременно (только один Сегмент является «активным» за раз.другой поток должен быть в состоянии выполнить Segment1, но не Segment2.

Edit 2
Учитывая все комментарии / ответы и мой сценарий реального мира, я понимаю, что это немного сумасшедшийтребовать, чтобы Segment2 был доступен для нескольких потоков.

Ответы [ 3 ]

4 голосов
/ 12 апреля 2011

Это довольно необычная модель для защиты ресурсов от неправильного одновременного доступа. Сначала я рассмотрю, нельзя ли преобразовать ваш сценарий использования в эквивалентный сценарий, в котором вы можете использовать простые блокировки.Если бы вы могли предоставить более подробную информацию о том, зачем вам нужна такая схема блокировки, сообщество может предложить другие идеи.

Чтобы ответить на ваш конкретный вопрос, ничего в .NET или даже в Win32 напрямуюподдерживает эту модель блокировки, , однако вы можете создать ее из других примитивов. Я бы посмотрел на использование пары ReaderWriterLockSlim экземпляров для защиты каждого ресурса.Когда потоки входят в сегмент A, вы получаете блокировку чтения на A и блокировку записи B ... и наоборот для потоков, входящих в сегмент B.Это позволило бы выполнять несколько потоков в каждом сегменте, но не одновременно .

РЕДАКТИРОВАТЬ : Учитывая ваш ответ в комментариях к вашему вопросу, я более убежден, что вам нужно взглянуть на использование модели блокировки Reader / Writer. What you 'поиск - это способ защитить ресурс, так что когда «писатели» выполняют работу (сериализацию словаря), в них не могут войти ни читатели, ни другие писатели, а когда «читатели» выполняют работу, они не блокируют друг друга, а блокируют все остальные.писатели.Это классический случай для блокировки чтения / записи.

РЕДАКТИРОВАТЬ 2 : Теперь, когда у меня есть больше времени, я думаю, что стоит остановиться на одном моменте.Способ думать о блокировках заключается в том, что они защищают ресурсы данных (память, файлы и т. Д.), А не области кода.Тот факт, что нам нужно определить критические разделы кода, в которые может войти только один поток за раз, - это деталь реализации, которую не следует путать с тем, как используются общие ресурсы (и должны быть защищены).В вашем вопросе основное внимание уделено тому, как контролировать, какие потоки могут входить, какой раздел кода отклоняется от реальной проблемы: какие ресурсы данных вы пытаетесь защитить от каких изменений.Если вы посмотрите на проблему с этой точки зрения, она прояснит, какие парадигмы реализации имеют смысл.

Вот несколько полезных ресурсов по моделям блокировки чтения / записи:

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

1 голос
/ 12 апреля 2011

Учитывая ваше редактирование, похоже, что правильным подходом будет использование ReaderWriterLockSlim , поскольку вам действительно не следует изменять коллекцию во время работы Segment2, и вы не должны допускать более 1Сегмент2 для запуска:

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();
    }
}
0 голосов
/ 12 апреля 2011

Вроде как.

    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 /

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...