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

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

 

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

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

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

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


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