Создание эффективных WIN32-приложений с учетом специфики 64-разрядной версии Windows


Атомарный доступ: семейство Inferlockect-функций - часть 3


// определяем глобальную переменную long g_x = 0;

DWORD WINAPI ThreadFunc1(PVOID pvParam) {
InterlockedExchangeAdd(&g_x, 1);
return(0); }

DWORD WINAPI ThreadFunc2(PVOID pvPararr) {
InterlockedExchangeAdd(&g_x, 1);
return(0); }

Теперь Вы можете быть уверены, что конечное значение g_x будет равно 2. Ну, Вам уже лучше? Заметьте: в любом потоке, где нужно модифицировать значение разделя емой (общей) переменной типа LONG, следует пользоваться лишь Interlocked-функ циями и никогда не прибегать к стандартным операторам языка С:

// переменная типа LONG, используемая несколькими потоками
LONG g_x;

// неправильный способ увеличения переменной типа LONG
g_x++;

// правильный способ увеличения переменной типа LONG
InterlockedExchangeAdd(&g_x, 1);

Как же работают Interlocked-функции? Ответ зависит от того, какую процессорную платформу Вы используете. На компьютерах с процессорами семейства x86 эти фун кции выдают по шине аппаратный сигнал, не давая другому процессору обратиться по тому же адресу памяти. На платформе Alpha Interlocked-функции действуют при мерно так:

  1. Устанавливают специальный битовый флаг процессора, указывающий, что дан ный адрес памяти сейчас занят.
  2. Считывают значение из памяти в регистр.
  3. Изменяют значение в регистре.
  4. Если битовый флаг сброшен, повторяют операции, начиная с п. 2. В ином слу чае значение из регистра помещается обратно в память.

Вас, наверное, удивило, с какой это стати битовый флаг может оказаться сброшен ным? Все очень просто. Его может сбросить другой процессор в системе, пытаясь модифицировать тот же адрес памяти, а это заставляет Interlocked-функции вернуть ся в п. 2.

Вовсе не обязательно вникать в детали работы этих функций. Вам нужно знать лишь одно: они гарантируют монопольное изменение значений переменных незави симо oт того, как именно компилятор генерирует код и сколько процессоров уста новлено в компьютере. Однако Вы должны позаботиться о выравнивании адресов переменных, передаваемых этим функциям, иначе они могут потерпеть неудачу, (О выравнивании данных я расскажу в главе 13.)




Начало  Назад  Вперед