Содержание материала

Защищенный доступ к переменным (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 для просмотра.

 

Добавить комментарий

Не использовать не нормативную лексику.

Просьба писать ваши замечания, наблюдения и все остальное,
что поможет улучшить предоставляемую информацию на этом сайте.

ВСЕ КОММЕНТАРИИ МОДЕРИРУЮТСЯ ВРУЧНУЮ, ТАК ЧТО СПАМИТЬ БЕСПОЛЕЗНО!


Защитный код
Обновить