"Критическая секция": функции Lock() и Unlock()
В прошлом выпуске я начал рассказывать о критических секциях и привел исходный код функций, с помощью которых эти критические секции реализуются: Lock() и Unlock().
В этом выпуске я хотел остановится на этих функциях подробнее.
Напомню, что критические секции используются для того, чтобы в каждый момент времени только один эксперт имел доступ к ресурсу (например, к переменной).
Критическая секция - это объект, который может находиться только в двух состояниях:
- "зеленый свет" (-1); и
- "красный свет" (1).
Перед использованием ресурса мы должны вызвать функцию Lock(). В качестве объекта "критическая секция" мы будем использовать глобальную переменную, имя которой содержится в переменной critical_section.
Первым делом в функции Lock() мы проверяем, существует ли "объект", т.е. глобальная переменная. Если она не существует, то мы ее создаем:
// проверим, существует ли переменная critical_section if (!GlobalVariableCheck(critical_section)) { if (GetLastError()!=0) return(1);
// переменная не существует, создадим ее if (GlobalVariableSet(critical_section, -1.0)==0) return(1); // переменная создана }
В случае каких-то ошибок вернем 1. При создании же переменной присвоим ей значение -1.0 ("зеленый свет").
Далее в течение timeout секунд в цикле пытаемся дождаться "зеленого света". По умолчанию ждем бесконечно (если параметр timeout равен нулю).
Чтобы не "зависнуть" в этом цикле, мы делаем ряд проверок. Прежде всего мы проверяем, не зажегся ли "зеленый свет". А если он зажегся, то пытаемся установить "красный свет":
// проверить, не загорелся ли "зеленый свет" if (GlobalVariableGet(critical_section)==-1.0) { // "зеленый свет" загорелся, зажигаем "красный свет" if (GlobalVariableSetOnCondition(critical_section, 1.0, -1.0)) return(0);
// нас опередили, поэтому ждем "зеленового света" }
Далее проверяем, не был ли остановлен эксперт:
// проверим, не остановлен ли эксперт if (IsStopped()) return(2);
Также проверим, не истекли ли наши timeout секунд:
// таймаут не истек? if (timeout!=0) { if ((GetTickCount()-StartTime)>timeout*1000) return(3); }
Если же пока нет повода прервать бесконечный цикл, то мы "спим" 0.1 секунды (функция Sleep) и повторяем все сначала.
Функция Unlock() работает по аналогии: проверяем, существует ли глобальная переменная и создаем ее, если надо:
// проверим, существует ли переменная critical_section if (!GlobalVariableCheck(critical_section)) { if (GetLastError()!=0) return(1);
// переменная не существует, создадим ее if (GlobalVariableSet(critical_section, -1.0)==0) return(1);
// переменная создана, поэтому выходим return(0); }
Далее в бесконечном цикле мы пытаемся установить "зеленый свет" и если нам это удалось, то выходим:
// бесконечный цикл while (true) { // пытаемся установить "зеленый свет" if (GlobalVariableSetOnCondition(critical_section, -1.0, 1.0)) return(0);
... }
Естественно, что также в цикле мы проверяем, не остановлен ли эксперт:
// проверим, не остановлен ли эксперт if (IsStopped()) return(2);
И проверяем, не истек ли таймаут:
if (timeout!=0) { if ((GetTickCount()-StartTime)>timeout*1000) return(3); }
Если нет повода выйти из цикла, то спим 0.1 секунды и повторяем все снова:
Sleep(100);
Пример использования функций Lock() и Unlock():
// вызываем Lock() перед началом работы с ресурсом Lock();
// работаем с ресурсом // ...
// вызываем Unlock() сразу же после завершения работы с ресурсом Unlock();
В следующем выпуске я продолжу изучение функций для работы с глобальными переменными.
Все статьи по теме "Пишем советников для MetaTrader 4".
- Механическая торговая система - миф или реальность?
- С чего начать при написании советника:
- Создаем нового советника - Настраиваем параметры. - Язык MetaQuotes Language 4: