Блокировка Чтения-записи Win32 Только Используя Критические Разделы

Я согласен с троичным оператором. Очень мало используется в коде, с которым я сталкиваюсь, и я думаю, что его гораздо легче и приятнее читать, чем все дополнительные скобки и отступы, необходимые для написания оператора if / else.

9
задан Dan Lorenc 17 June 2009 в 18:17
поделиться

6 ответов

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

Критические разделы действительно обеспечивают блокировку, но API слишком ограничен. например, вы не можете захватить CS, обнаружите, что доступна блокировка чтения, но не блокировка записи, и дождитесь, пока другой процесс закончит чтение (потому что, если другой процесс имеет критическую секцию, он заблокирует других читателей, что неверно, и если это не значит, что ваш процесс не будет блокироваться, а будет вращаться, сжигая циклы ЦП.)

Однако вы можете использовать спин-блокировку и возвращаться к мьютексу всякий раз, когда возникает конфликт. Сам критический раздел реализован таким образом.

6
ответ дан 4 December 2019 в 07:14
поделиться

Взгляните на книгу « Параллельное программирование в Windows », в которой есть множество различных справочных примеров для читателя / писатель блокирует.

3
ответ дан 4 December 2019 в 07:14
поделиться

Обратите внимание на spin_rw_mutex из Intel Thread Building Blocks ...

spin_rw_mutex строго в области пользователя и использует спин-ожидание для блокировки

3
ответ дан 4 December 2019 в 07:14
поделиться

Если вы можете настроить Vista или выше, вы должны использовать встроенный SRWLock . Они легкие, как критические разделы, полностью в пользовательском режиме, когда нет разногласий.

В блоге Джо Даффи есть несколько недавних записей о реализации различных типов неблокирующих блокировок чтения / записи. Эти замки вращаются, поэтому они не подходят, если вы собираетесь много работать, удерживая замок. Код написан на C #, но должен быть простым для переноса на собственный.

Вы можете реализовать блокировку чтения / записи, используя критические разделы и события - вам просто нужно поддерживать достаточно состояния, чтобы сигнализировать о событии только тогда, когда это необходимо, чтобы избежать ненужного ядра вызов режима.

12
ответ дан 4 December 2019 в 07:14
поделиться

If you already know of a solution that only uses mutexes, you should be able to modify it to use critical sections instead.

We rolled our own using two critical sections and some counters. It suits our needs - we have a very low writer count, writers get precedence over readers, etc. I'm not at liberty to publish ours but can say that it is possible without mutexes and semaphores.

0
ответ дан 4 December 2019 в 07:14
поделиться

Вот наименьшее решение, которое я мог придумать:

http://www.baboonz.org/rwlock.php

И дословно вставлено:

/** A simple Reader/Writer Lock.

This RWL has no events - we rely solely on spinlocks and sleep() to yield control to other threads.
I don't know what the exact penalty is for using sleep vs events, but at least when there is no contention, we are basically
as fast as a critical section. This code is written for Windows, but it should be trivial to find the appropriate
equivalents on another OS.

**/
class TinyReaderWriterLock
{
public:
    volatile uint32 Main;
    static const uint32 WriteDesireBit = 0x80000000;

    void Noop( uint32 tick )
    {
        if ( ((tick + 1) & 0xfff) == 0 )     // Sleep after 4k cycles. Crude, but usually better than spinning indefinitely.
            Sleep(0);
    }

    TinyReaderWriterLock()                 { Main = 0; }
    ~TinyReaderWriterLock()                { ASSERT( Main == 0 ); }

    void EnterRead()
    {
        for ( uint32 tick = 0 ;; tick++ )
        {
            uint32 oldVal = Main;
            if ( (oldVal & WriteDesireBit) == 0 )
            {
                if ( InterlockedCompareExchange( (LONG*) &Main, oldVal + 1, oldVal ) == oldVal )
                    break;
            }
            Noop(tick);
        }
    }

    void EnterWrite()
    {
        for ( uint32 tick = 0 ;; tick++ )
        {
            if ( (tick & 0xfff) == 0 )                                     // Set the write-desire bit every 4k cycles (including cycle 0).
                _InterlockedOr( (LONG*) &Main, WriteDesireBit );

            uint32 oldVal = Main;
            if ( oldVal == WriteDesireBit )
            {
                if ( InterlockedCompareExchange( (LONG*) &Main, -1, WriteDesireBit ) == WriteDesireBit )
                    break;
            }
            Noop(tick);
        }
    }

    void LeaveRead()
    {
        ASSERT( Main != -1 );
        InterlockedDecrement( (LONG*) &Main );
    }
    void LeaveWrite()
    {
        ASSERT( Main == -1 );
        InterlockedIncrement( (LONG*) &Main );
    }
};
0
ответ дан 4 December 2019 в 07:14
поделиться
Другие вопросы по тегам:

Похожие вопросы: