"Критическая секция": функции 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: