Защищенный доступ к переменным (Interlocked Variable Access)
Часто возникает необходимость совершения операций над разделяемыми между потоками 32-разрядными переменными. Для упрощения решения этой задачи WinAPI предоставляет функции для защищенного доступа к ним, не требующие использования дополнительных (и более сложных) механизмов синхронизации. Переменные, используемые в этих функциях, должны быть выровнены на границу 32-разрядного слова. Применительно к Delphi это означает, что если переменная объявлена внутри записи (record), то эта запись не должна быть упакованной (packed) и при её объявлении должна быть активна директива компилятора {$A+}. Несоблюдение этого требования может привести к возникновению ошибок на многопроцессорных конфигурациях.
Code: |
type TPackedRecord = packed record A: Byte; B: Integer; end; // TPackedRecord.B нельзя использовать в функциях InterlockedXXX
TNotPackedRecord = record A: Byte; B: Integer; end;
{$A-} var A1: TNotPackedRecord; // A1.B нельзя использовать в функциях InterlockedXXX I: Integer // I можно использовать в функциях InterlockedXXX, т.к. переменные в // Delphi всегда выравниваются на границу слова безотносительно // к состоянию директивы компилятора $A
{$A+} var A2: TNotPackedRecord; // A2.B можно использовать в функциях InterlockedXXX
function InterlockedIncrement( var Addend: Integer ): Integer; stdcall; |
Функция увеличивает переменную Addend на 1. Возвращаемое значение зависит от операционной системы:
Windows 98, Windows NT 4.0 и старше
Возвращается новое значение переменной Addend
Windows 95, Windows NT 3.51
Если после изменения Addend < 0 возвращается отрицательное число, не обязательно равное Addend Если Addend = 0 – возвращается 0 Если после изменения Addend > 0 возвращается положительное число, не обязательно равное Addend.
function InterlockedDecrement(
var Addend: Integer
): Integer; stdcall;
Функция уменьшает переменную Addend на 1. Возвращаемое значение аналогично функции InterlockedIncrement.
function InterlockedExchange(
var Target: Integer;
Value: Integer
): Integer; stdcall;
Функция записывает в переменную Target значение Value и возвращает предыдущее значение Target
Следующие функции для выполнения требуют Windows 98 или Windows NT 4.0 и старше.
function InterlockedCompareExchange(
var Destination: Pointer;
Exchange: Pointer;
Comperand: Pointer
): Pointer; stdcall;
Функция сравнивает значения Destination и Comperand. Если они совпадают, значение Exchange записывается в Destination. Функция возвращает начальное значение Destination.
function InterlockedExchangeAdd(
Addend: PLongint;
Value: Longint
): Longint; stdcall;
Функция добавляет к переменной, на которую указывает Addend значение Value и возвращает начальное значение Addend.
Резюме
Многозадачная и многопоточная среда Win32 предоставляет широкие возможности для написания высокоэффективных приложений. Однако, написание приложений, использующих многопоточность и взаимодействующих друг с другом, при неаккуратном программировании может привести к их неверной работе, неоправданной загрузке и даже блокировке всей системы. Во избежание этого следуйте нижеприведенным рекомендациям:
• | Если приложения или потоки одного процесса изменяют общий ресурс – защищайте доступ к нему при помощи критических секций или мутексов. |
• | Если доступ осуществляется только на чтение – защищать ресурс не обязательно. |
• | Критические секции более эффективны, но применимы только внутри одного процесса, мутексы могут использоваться для синхронизации между процессами. |
• | Используйте семафоры для ограничения количества обращений к одному ресурсу. |
• | Используйте события (event) для информирования потока о наступлении какого-либо события. |
• | Если разделяемый ресурс – 32-битная переменная – для синхронизации доступа к нему можно использовать функции, обеспечивающие разделяемый доступ к переменным. |
• | Многие объекты Win32 позволяют организовать эффективное слежение за своим состоянием при помощи функций ожидания. Это наиболее эффективный с точки зрения расхода системных ресурсов метод. |
• | Если Ваш поток создает (даже неявно, при помощи CoInitialize или функций DDE) окна – он должен обрабатывать сообщения. Не используйте в таком потоке функций не позволяющих прервать ожидание по приходу сообщения с большим или неограниченным периодом ожидания. Используйте функции MsgWaitForXXX |
Тенцер А. Л.
ICQ UIN 15925834
Этот адрес электронной почты защищён от спам-ботов. У вас должен быть включен JavaScript для просмотра.
- << Назад
- Вперёд
Просьба писать ваши замечания, наблюдения и все остальное,
что поможет улучшить предоставляемую информацию на этом сайте.
ВСЕ КОММЕНТАРИИ МОДЕРИРУЮТСЯ ВРУЧНУЮ, ТАК ЧТО СПАМИТЬ БЕСПОЛЕЗНО!